zoukankan      html  css  js  c++  java
  • BZOJ 4479: [Jsoi2013]吃货jyy

    一句话题意:求必须包含某K条边的回路(回到1),使得总权值最小

    转化为权值最小的联通的偶点

    令F[i]表示联通状态为i的最小权值,(3^n状压)表示不在联通块内/奇点/偶点,连边时先不考虑必选的边的度数和权值

    最后加上必须的边(保证必须的边都被选了)

    连完这些边以后考虑剩下的一些奇点,两两配对,G[i]表示状态为i的奇点两两配对的代价(2^n状压)

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int cnt,n,k,last[15],dis[15][15],G[10005],F[2000005],vis[15],a[15],mi[15];
    struct node{
    	int to,next;
    }e[1000005];
    void add(int a,int b){
    	e[++cnt].to=b;
    	e[cnt].next=last[a];
    	last[a]=cnt;
    }
    int main(){
    	scanf("%d%d",&n,&k);
    	for (int i=0; i<n; i++)
    		for (int j=0; j<n; j++)
    			dis[i][j]=1e9;
    	int ans=0;
    	for (int i=1; i<=k; i++){
    		int x,y,z;
    		scanf("%d%d%d",&x,&y,&z);
    		x--,y--;
    		add(x,y);
    		add(y,x);
    		ans+=z;
    		vis[x]++;
    		vis[y]++;
    		dis[x][y]=min(dis[x][y],z);
    		dis[y][x]=min(dis[y][x],z);
    	}
    	int m;
    	scanf("%d",&m);
    	for (int i=1; i<=m; i++){
    		int x,y,z;
    		scanf("%d%d%d",&x,&y,&z);
    		x--,y--;
    		dis[x][y]=min(dis[x][y],z);
    		dis[y][x]=min(dis[y][x],z);
    	}
    	for (int k=0; k<n; k++)
    		for (int i=0; i<n; i++)
    			for (int j=0; j<n; j++)
    				dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    	for (int i=0; i<(1<<n); i++) G[i]=1e9;
    	G[0]=0;
    	for (int i=0; i<(1<<n); i++)
    		for (int x=0; x<n; x++)
    			if (!(i&(1<<x))){
    				for (int y=x+1; y<n; y++)
    					if (!(i&(1<<y))) 
    						G[i|(1<<x)|(1<<y)]=min(G[i|(1<<x)|(1<<y)],G[i]+dis[x][y]);
    			}
    	mi[0]=1;
    	for (int i=1; i<=n; i++) mi[i]=mi[i-1]*3;
    	for (int i=0; i<mi[n]; i++) F[i]=1e9;
    	F[2]=0;
    	for (int now=2; now<mi[n]; now++)
    		if (F[now]!=1e9){
    			int N=0;
    			for (int i=0; i<n; i++) if (now/mi[i]%3) a[N++]=i;
    			for (int i=0; i<n; i++)
    				if (!(now/mi[i]%3)){
    					for (int j=last[i]; j; j=e[j].next){
    						int V=e[j].to;
    						if (now/mi[V]%3){
    							int To=now+mi[i]*2;
    							F[To]=min(F[To],F[now]);
    						}
    					}
    					for (int j=0; j<N; j++){
    						int To=now+mi[i];
    						if (now/mi[a[j]]%3==1) To+=mi[a[j]];
    						else if (now/mi[a[j]]%3==2) To-=mi[a[j]];
    						F[To]=min(F[To],F[now]+dis[i][a[j]]);
    					}
    				}
    		}
    	int ANS=1e9;
    	for (int now=0; now<mi[n]; now++){
    		int flag=0,Now=now;
    		for (int i=0; i<n; i++) if (vis[i] && !(Now/mi[i]%3)){
    			flag=1;
    			break;
    		}
    		if (flag) continue;
    		for (int i=0; i<n; i++) 
    			if (vis[i]&1){
    				if (Now/mi[i]%3==1) Now+=mi[i];
    				else if (Now/mi[i]%3==2) Now-=mi[i];
    			}
    		int To=0;
    		for (int i=0; i<n; i++) if (Now/mi[i]%3==1) To|=(1<<i);
    		ANS=min(ANS,F[now]+G[To]);
    	}
    	printf("%d
    ",ans+ANS);
    	return 0;
    }
    

      

  • 相关阅读:
    Git/GitHub使用技巧
    《暗时间》第一遍读书心得整理
    学习方法摘要总结
    Py爬虫项目
    2018年6月12日
    狐狸坑蛋糕
    Codeforces 371C Hanburgers
    【别忘咯】 关于运算优先级
    【noip 2009】 乌龟棋 记忆化搜索&动规
    【Openjudge】 算24
  • 原文地址:https://www.cnblogs.com/silenty/p/9879580.html
Copyright © 2011-2022 走看看