• 【20190710】简单题


    题目

    这是一道提交答案题

    给出一个(n)个点(m)条边的无向图

    可以删除(K)条边

    询问一个删边方案使得最短路的最大值

    题解

    TAT我一整天的时光啊........................................

    • data 1,2,3

      测试点范围较小

      可以直接做spfa找最短路,接着删除1~n最短路径上的某条边,重复多次直到不能删除

      选边的时候需要先随机一个扰动概率P,对不同的点调整一下P多跑几次即可

      #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
      ",i);
      	return 0;
      }
      
    • data 4,5

      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
      ",i);
      	return 0;
      }
      
    • data 6,7

      data 6,7也是很多块,每个块10个点,10/20条边

      可以先((2^{20}))暴力枚举删除的边做spfa(由于删边多的时候路径少所以速度不慢)

      由于删边数有限制,所以dp处理,时间复杂度:(O( frac{n}{10}(2^{20} imes 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
      ",i);
      	return 0;
      }//
      
    • data 8

      是个(100 imes 100)的网格图,边权为1

      • 证明(2n imes2n)的网格图不存在一条((1,1) o(2n,2n))的哈密顿路径

        黑白染色后(1,1)和(2n,2n)同色,这说明如果路径存在,黑!=白,矛盾

      可以用一下方式构造一个长度为9998的路径

      • 假设构造好了 (i imes 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
    ",i);
    	return 0;
    }
    
    • data 9

      (2 imes 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
    ",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
    ",tot);
    	for(int i=1;i<=m;++i)if(vis[i])printf("%d
    ",i);
    	return 0;
    }
    
  • 相关阅读:
    FastAPI 学习之路(十九)处理错误
    FastAPI 学习之路(二十六)全局依赖项
    FastAPI 学习之路(二十)接口文档配置相关
    FastAPI 学习之路(二十二)依赖项
    FastAPI 学习之路(二十一)请求体 更新数据
    FastAPI 学习之路(二十四)子依赖项
    Never worry about ASP.NET AJAX’s .d again
    Java C格式输入利用printf函数
    Oracle正则表达式函数
    javascript 事件驱动编程【转(原文为“事件驱动的javascript”)】
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/11171303.html
Copyright © 2020-2023  润新知