【20190710】簡單題

題目

這是一道提交答案題c++

給出一個\(n\)個點\(m\)條邊的無向圖dom

能夠刪除\(K\)條邊測試

詢問一個刪邊方案使得最短路的最大值ui

題解

TAT我一成天的時光啊........................................spa

  • data 1,2,3code

    測試點範圍較小get

    能夠直接作spfa找最短路,接着刪除1~n最短路徑上的某條邊,重複屢次直到不能刪除it

    選邊的時候須要先隨機一個擾動機率P,對不一樣的點調整一下P多跑幾回便可class

    #include<bits/stdc++.h>
    #define inf 0x3f3f3f3f
    #define ld double
    using namespace std;
    const int N=11000;
    int n,m,K,dis[N],vis[N],del[N<<1],hd[N],o,Ans[N],ans,tot,pre[N];
    queue<int>q;
    struct Edge{int u,v,nt,w,id;}E[N<<1];
    void adde(int u,int v,int w,int id){
      E[o]=(Edge){u,v,hd[u],w,id};hd[u]=o++;
      E[o]=(Edge){v,u,hd[v],w,id};hd[v]=o++;
    }
    int spfa(){
      for(int i=1;i<=n;++i)dis[i]=inf;
      dis[1]=0;vis[1]=1;q.push(1);
      while(!q.empty()){
          int u=q.front();q.pop();
          vis[u]=0;
          for(int i=hd[u];~i;i=E[i].nt)if(!del[i]){
              int v=E[i].v;
              if(dis[v]>dis[u]+E[i].w){
                  dis[v]=dis[u]+E[i].w;pre[v]=i;
                  if(!vis[v])q.push(v),vis[v]=1;
              }
          }
      }
      if(dis[n]==inf)return -1;
      if(dis[n]>ans){
          ans=dis[n];tot=0;
          for(int i=1;i<=m;++i)Ans[i]=0;
          for(int i=0;i<o;i+=2)if(del[i]){
              Ans[E[i].id]=1;
              tot++;
          }
      }
      return dis[n];
    }
    int calc(ld P){
      static int top,sta[N];
      int res=K,mxp=0;
      for(int i=0;i<o;i++)del[i]=0;
      while(res){
          int now=spfa();if(!~now)break;
          mxp=max(now,mxp);
    
          top=0;for(int u=n;u!=1;u=E[pre[u]].u)sta[++top]=pre[u];
          random_shuffle(sta+1,sta+top+1);
    
          for(int I=1;I<=top;++I){
              int i=sta[I];
              if(del[i]||rand()<=RAND_MAX*P)continue;
              del[i]=del[i^1]=1;res--;
              break;
          }
    
      }
      int now=spfa();
      if(~now)mxp=max(mxp,now);
      return mxp;
    }
    void solve(){
      ld P=0.66666666666;
      for(int i=0;;++i){
      //  P+=1.0/100000;
          calc(P);
          //calc(P);
          if(ans>=189626)break;
          cerr<<i<<" "<<ans<<endl;
      }
    }
    int main(){
      srand(time(NULL));
      freopen("shortest4.in","r",stdin);
    //    freopen("shortest2.out","w",stdout);
      scanf("%d%d%d",&n,&m,&K);
      for(int i=1;i<=n;++i)hd[i]=-1;
      for(int i=1;i<=m;++i){
          int u,v,w;
          scanf("%d%d%d",&u,&v,&w);
          adde(u,v,w,i);
      }
      solve();
      cerr<<ans<<endl;
      cout<<tot<<endl;
      for(int i=1;i<=m;++i)if(Ans[i])printf("%d\n",i);
      return 0;
    }
  • data 4,5test

    data 4 \(n \le 20\) 直接狀壓\(dp\),時間複雜度\(O(2^n n^2)\)

    data 5 每20個點組成一塊,套用data 4的dp

    #include<bits/stdc++.h>
    #define mk make_pair
    #define inf 0x3f3f3f3f
    using namespace std;
    const int N=20,M=1000010;
    int n,m,K,w[N][N],e[N][N],vis[M],tot,sum;
    int f[N][1<<N],h[N][1<<N],V,E;
    pair<int,int>g[N][1<<N];
    void get_path(int x,int y){
      for(;x;){
          int tx,ty;
          vis[h[x][y]]=1;
          tx=g[x][y].first;
          ty=g[x][y].second;
          swap(tx,x);swap(ty,y);
      }
    }//
    void solve(){
      for(int i=0;i<20;++i)
      for(int j=0;j<20;++j)w[i][j]=-inf,e[i][j]=-1;
    
      for(++E;E<=m;++E){
          int u,v,x;
          scanf("%d%d%d",&u,&v,&x);
          if(v>V+20){sum+=x;vis[E]=1;break;}
          u-=V+1;v-=V+1;
          if(w[u][v]<x)w[u][v]=w[v][u]=x,e[u][v]=e[v][u]=E;
      }
    
      for(int i=0;i<1<<20;++i)
      for(int j=0;j<20;++j)f[j][i]=-inf;
      f[0][1]=0;
    
      for(int i=1;i<1<<20;++i)
      for(int j=0;j<20;++j)if(i>>j&1)
      for(int k=0;k<20;++k)if(!(i>>k&1)){
          int t=i^(1<<k);
          if(f[k][t]<f[j][i]+w[j][k]){
              f[k][t]=f[j][i]+w[j][k];
              h[k][t]=e[j][k];
              g[k][t]=mk(j,i);
          }
      }
    
      int pos=0;
      for(int i=1;i<1<<20;++i)if(f[19][pos]<f[19][i])pos=i;
      sum+=f[19][pos];
      cerr<<sum<<endl;
      get_path(19,pos);
    
      V+=20;
    }
    int main(){
      freopen("shortest5.in","r",stdin);
      freopen("shortest5.out","w",stdout);
      scanf("%d%d%d",&n,&m,&K);
      for(int i=0;i<n;i+=20)solve();
      tot=m;for(int i=1;i<=m;++i)tot-=vis[i];
      cout<<tot<<endl;
      for(int i=1;i<=m;++i)if(!vis[i])printf("%d\n",i);
      return 0;
    }
  • data 6,7

    data 6,7也是不少塊,每一個塊10個點,10/20條邊

    能夠先\((2^{20})\)暴力枚舉刪除的邊作spfa(因爲刪邊多的時候路徑少因此速度不慢)

    因爲刪邊數有限制,因此dp處理,時間複雜度:\(O( \frac{n}{10}(2^{20}\times SPFA + \ K^2))\)

    #include<bits/stdc++.h> 
    #define mk make_pair
    #define inf 0x3f3f3f3f
    using namespace std;
    const int N=21,M=1000010;
    int n,m,K,B,vis[N],dis[N],o,hd[N],tot,sum,nV,nE,del[N<<1];
    int f[101][1001],g[101][1001],h[101][1001],val[N],pos[N],Ans[M];
    struct Edge{int v,nt,w;}E[N<<1];
    void adde(int u,int v,int w){
      E[o]=(Edge){v,hd[u],w};hd[u]=o++;
      E[o]=(Edge){u,hd[v],w};hd[v]=o++;
    }
    queue<int>q;
    int spfa(){
      for(int i=1;i<=10;++i)dis[i]=inf;
      dis[1]=0;vis[1]=1;q.push(1);
      while(!q.empty()){
          int u=q.front();q.pop();
          vis[u]=0;
          for(int i=hd[u];~i;i=E[i].nt)if(!del[i]){
              int v=E[i].v;
              if(dis[v]>dis[u]+E[i].w){
                  dis[v]=dis[u]+E[i].w;
                  if(!vis[v])q.push(v),vis[v]=1;
              }
          }
      }
      return dis[10]==inf?-inf:dis[10];
    }
    void get_path(int x,int y){
      if(!x)return ;
      int S=g[x][y],base=(x-1)*(B+1);
      for(int i=0;i<B;++i)if(S>>i&1)Ans[base+i+1]=1,tot++;
      get_path(x-1,h[x][y]);
    }
    void solve(int I){
      o=0;for(int i=1;i<=10;++i)hd[i]=-1;
    
      int con=0;
      for(++nE;nE<=m;++nE){
          int u,v,w;
          scanf("%d%d%d",&u,&v,&w);
          if(v>nV+10){con=w;break;}
          u-=nV;v-=nV;adde(u,v,w);
      }
    
      for(int i=0;i<=B;++i)val[i]=-inf;
      for(int i=0;i<1<<B;++i){
          for(int j=0;j<o;++j)del[j]=i>>(j>>1)&1;
          int tmp=spfa(); 
          int cnt=__builtin_popcount(i);
          if(val[cnt]<tmp){val[cnt]=tmp;pos[cnt]=i;}
      }
    
      for(int i=0;i<=K;++i)
      for(int j=0;j<=i&&j<=B;++j){
          if(f[I][i]<f[I-1][i-j]+val[j]+con){
              f[I][i]=f[I-1][i-j]+val[j]+con;
              g[I][i]=pos[j];h[I][i]=i-j;
          }
      }
    
      cerr<<f[I][K]<<endl;    
    }
    int main(){
      freopen("shortest7.in","r",stdin);
      freopen("shortest7.out","w",stdout);
      scanf("%d%d%d",&n,&m,&K);B=(m-99)/(n/10);
      for(int i=1;i<=100;++i)
      for(int j=0;j<=K;++j)f[i][j]=-inf;
      int I;for(I=1;nV<n;++I,nV+=10)solve(I);
      get_path(--I,K);
      cout<<tot<<endl;
      for(int i=1;i<=m;++i)if(Ans[i])printf("%d\n",i);
      return 0;
    }//
  • data 8

    是個\(100 \times 100\)的網格圖,邊權爲1

    • 證實\(2n\times2n\)的網格圖不存在一條\((1,1)\to(2n,2n)\)的哈密頓路徑

      黑白染色後(1,1)和(2n,2n)同色,這說明若是路徑存在,黑!=白,矛盾

    能夠用一下方式構造一個長度爲9998的路徑

    • 假設構造好了 \(i\times i\) ,如今在 \((i,i)\) ,而且長度爲 \(i^2 - 2\)
    • 能夠沒有遺漏地蛇行走到 \((i+1,i+1)\) ,具體細節見代碼
#include<bits/stdc++.h>
#define mk make_pair
using namespace std;
const int N=20010,M=110;
int n,m,K,B,tx,ty,vis[N],id[M][M],tot;
map<pair<int,int>,int>mp;
void put(int x,int y){
    cerr<<x<<" "<<y<<endl;
    if(x>y)swap(x,y);
    vis[mp[mk(x,y)]]=1;tot--;
}
int main(){
    freopen("shortest8.in","r",stdin);
    freopen("shortest8.out","w",stdout);
    scanf("%d%d%d",&n,&m,&K);
    for(int i=1,u,v,w;i<=m;++i){
        scanf("%d%d%d",&u,&v,&w);
        mp[mk(u,v)]=i;
    }
    B=sqrt(n+1);
    for(int i=1;i<=B;++i)
    for(int j=1;j<=B;++j){
        id[i][j]=(i-1)*B+j;
    }
    tot=m;
    put(id[1][1],id[1][2]);
    put(id[1][2],id[tx=2][ty=2]);
    for(int i=2;i<B;i+=2){
        put(id[tx][ty],id[tx+1][ty]);
        for(tx++;ty>1;--ty)put(id[tx][ty],id[tx][ty-1]);
        put(id[tx][ty],id[tx+1][ty]);
        for(tx++;ty<=i;++ty)put(id[tx][ty],id[tx][ty+1]);
        for(;tx>1;--tx)put(id[tx][ty],id[tx-1][ty]);
        put(id[tx][ty],id[tx][ty+1]);
        for(++ty;tx<i+2;++tx)put(id[tx][ty],id[tx+1][ty]);
    }
    //cerr<<tx<<" "<<ty<<endl;
    cerr<<m-tot<<endl;
    cout<<tot<<endl;
    for(int i=1;i<=m;++i)if(!vis[i])printf("%d\n",i);
    return 0;
}
  • data 9

    \(2\times 1000\)的網格圖,邊權不爲1,一些邊已經被刪除

    必定不會往回走,直接\(dp\)便可,爲了偷懶我直接拆點而後把上面的spfa拷過來了....

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ld double
using namespace std;
const int N=4010;
int n,m,K,dis[N],vis[N],hd[N],o,Ans[N],tot,pre[N<<1];
queue<int>q;
struct Edge{int u,v,nt,w,id;}E[N<<1];
void add(int u,int v,int w,int id){E[o]=(Edge){u,v,hd[u],w,id};hd[u]=o++;}
int spfa(){
    for(int i=1;i<=n;++i)dis[i]=-inf;
    dis[1]=0;vis[1]=1;q.push(1);
    while(!q.empty()){
        int u=q.front();q.pop();
        vis[u]=0;
        for(int i=hd[u];~i;i=E[i].nt){
            int v=E[i].v;
            if(dis[v]<dis[u]+E[i].w){
                pre[v]=i;
                dis[v]=dis[u]+E[i].w;pre[v]=i;
                if(!vis[v])q.push(v),vis[v]=1;
            }
        }
    }
    return dis[n];
}
int main(){
    srand(time(NULL));
    freopen("shortest9.in","r",stdin);
    freopen("shortest9.out","w",stdout);
    scanf("%d%d%d",&n,&m,&K);
    for(int i=1;i<=n<<1;++i)hd[i]=-1;
    for(int i=1;i<=n;++i)add(i,i+n,0,0);
    for(int i=1;i<=m;++i){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        if(u>v)swap(u,v);
        if(v!=u+1){
            add(v,u+n,w,i);
            add(u,v+n,w,i);
        }else add(u+n,v,w,i);
    }
    n<<=1;
    cerr<<spfa()<<endl;
    for(int i=n;i!=1;i=E[pre[i]].u)Ans[E[pre[i]].id]=1;
    tot=m;for(int i=1;i<=m;++i)tot-=Ans[i];
    cout<<tot<<endl;
    for(int i=1;i<=m;++i)if(!Ans[i])printf("%d\n",i);
    return 0;
}
  • data 10

    存在哈密頓迴路

    圖比較稀疏而且輸出deg=3的點的個數能夠發現多餘的邊,沒有公共點!

    誒,居然直接把兩邊都deg=3的邊都刪掉就能夠出解了

#include<bits/stdc++.h>
using namespace std;
const int N=10100;
int n,m,K,vis[N],cnt,fg,d[N];
struct edge{int u,v,w;}e[N];
vector<pair<int,int> >G[N];
stack<int>Ans;
void dfs(int u){
    if(fg)return;
    if(cnt==n&&u==n){fg=1;return;}
    for(auto  v : G[u])if(!vis[v.first]){
        cnt++;
        Ans.push(v.second);
        vis[v.first]=1;
        dfs(v.first);
        if(fg)return;
        vis[v.first]=0;
        Ans.pop();
        cnt--;
    }
}
int main(){
    freopen("shortest10.in","r",stdin);
    freopen("shortest10.out","w",stdout);
    scanf("%d%d%d",&n,&m,&K);
    for(int i=1;i<=m;++i){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        e[i]=(edge){u,v,w};
        //G[u].push_back(make_pair(v,i));
        //G[v].push_back(make_pair(u,i));
        d[u]++;d[v]++;
    }
    //d[1]++;d[n]++;
    /*int mxd=0,mxc=0;
    for(int i=1;i<=m;++i){
        if(mxd<d[i])mxd=d[i],mxc=1;
        else if(mxd==d[i])mxc++;
    }
    cerr<<mxd<<" "<<mxc<<endl;
    */
    //cnt=1;dfs(1);
    //int tot=m;
    //for(int i=1;i<n;++i)vis[Ans.top()]=1,Ans.pop(),tot--;
    int tot=0;
    for(int i=1;i<=m;++i)if(d[e[i].u]==3&&d[e[i].v]==3){
        tot++,vis[i]=1;
        d[e[i].u]--;d[e[i].v]--;
    }
    printf("%d\n",tot);
    for(int i=1;i<=m;++i)if(vis[i])printf("%d\n",i);
    return 0;
}
相關文章
相關標籤/搜索