题意:给你n个城市,m条被摧毁的道路,每条道路修复需要c元,总共有k元,给你每个城市的人口,问在总费用不超过k的情况下 与1号城市相连的城市的最大总人口(包括1号城市)
思路:1号城市是必取的,剩余最多15个城市,枚举每个城市与一号城市的联通状态,共有2^15种,每一种情况跑最小生成树。
代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 using namespace std; 5 const int N=20,INF=0x3f3f3f3f; 6 int p[N],mark[N],a[N][N],low[N],z[N]; 7 int n,m,k,ans,sum; 8 int prim() 9 { 10 int i,j,ans=0; 11 memset(p,0,sizeof(p)); 12 p[1]=1; 13 for(j=2;j<=n;j++) 14 { 15 if(mark[j]) 16 low[j]=a[1][j]; 17 } 18 for(i=1;i<n;i++) 19 { 20 int mi=INF,po; 21 for(j=1;j<=n;j++) 22 { 23 if(!p[j]&&mark[j]&&low[j]<mi) 24 mi=low[j],po=j; 25 } 26 if(mi==INF)break; 27 p[po]=1; 28 ans+=mi; 29 for(j=1;j<=n;j++) 30 { 31 if(!p[j]&&mark[j]&&low[j]>a[po][j]) 32 low[j]=a[po][j]; 33 } 34 } 35 sum=0; 36 for(i=1;i<=n;i++) 37 if(p[i]&&mark[i])//标记了的点才可以算进总人口 38 sum+=z[i]; 39 return ans; 40 } 41 void dfs(int d) 42 { 43 if(d>n) 44 { 45 int cnt=prim(); 46 if(sum>ans&&cnt<=k) 47 ans=sum; 48 return ; 49 } 50 mark[d]=1;dfs(d+1); 51 mark[d]=0;dfs(d+1); 52 } 53 int main() 54 { 55 int i,j,u,v,w,t; 56 scanf("%d",&t); 57 while(t--) 58 { 59 scanf("%d%d%d",&n,&m,&k); 60 memset(a,0x3f,sizeof(a)); 61 for(i=1;i<=n;i++) 62 scanf("%d",&z[i]); 63 while(m--) 64 { 65 scanf("%d%d%d",&u,&v,&w); 66 if(w<a[u][v]) 67 a[u][v]=a[v][u]=w; 68 } 69 ans=0;mark[1]=1; 70 dfs(2); 71 printf("%d ",ans); 72 } 73 return 0; 74 }
上面的代码枚举是通过搜索,下面一种是通过位运算。
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 using namespace std; 5 const int N=20,INF=0x3f3f3f3f; 6 int p[N],mark[N],a[N][N],low[N],z[N]; 7 int n,m,k,ans,sum; 8 int prim(int x) 9 { 10 int i,j,ans=0; 11 for(i=1;i<=n;i++) 12 { 13 mark[i]=x&1; 14 x>>=1; 15 } 16 memset(p,0,sizeof(p)); 17 p[1]=1; 18 for(j=2;j<=n;j++) 19 { 20 if(mark[j]) 21 low[j]=a[1][j]; 22 } 23 for(i=1;i<n;i++) 24 { 25 int mi=INF,po; 26 for(j=1;j<=n;j++) 27 { 28 if(!p[j]&&mark[j]&&low[j]<mi) 29 mi=low[j],po=j; 30 } 31 if(mi==INF)break; 32 p[po]=1; 33 ans+=mi; 34 for(j=1;j<=n;j++) 35 { 36 if(!p[j]&&mark[j]&&low[j]>a[po][j]) 37 low[j]=a[po][j]; 38 } 39 } 40 sum=0; 41 for(i=1;i<=n;i++) 42 if(p[i]&&mark[i]) 43 sum+=z[i]; 44 return ans; 45 } 46 int main() 47 { 48 int i,j,u,v,w,t; 49 scanf("%d",&t); 50 while(t--) 51 { 52 scanf("%d%d%d",&n,&m,&k); 53 memset(a,0x3f,sizeof(a)); 54 for(i=1;i<=n;i++) 55 scanf("%d",&z[i]); 56 while(m--) 57 { 58 scanf("%d%d%d",&u,&v,&w); 59 if(w<a[u][v]) 60 a[u][v]=a[v][u]=w; 61 } 62 ans=0; 63 for(i=1;i<=(1<<n)-1;i++) 64 { 65 if(i&1) 66 { 67 int tmp=prim(i); 68 if(tmp<=k&&sum>ans) 69 ans=sum; 70 } 71 } 72 printf("%d ",ans); 73 } 74 return 0; 75 }