這是一道提交答案題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的路徑
#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; }