• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
L&King
有何不可!
   首页    新随笔    联系   管理    订阅  订阅

CSU 1116 Kingdoms

题意:给你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\n",ans);
72     }
73     return 0;
74 } 
View Code

上面的代码枚举是通过搜索,下面一种是通过位运算。

 

 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\n",ans);
73     }
74     return 0;
75 } 
View Code

 

posted @ 2016-05-13 10:27  L&King  阅读(182)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3