2019 西安邀请赛 D

复制代码
 1 //n件物品,m种关系,(有关系的2个不能在同一组)
 2 //把所有物品分为2组,希望最后2组的差值尽可能小,输出较大者
 3 /*
 4 二分图涂色+可行性(01)背包
 5 dp[i]  =1表示 最后差值为i可行
 6 建图后,对于每个连通分量记录差值,来求所有的可行
 7 */
 8 #include<bits/stdc++.h>
 9 using namespace std;
10 int  t,n,m;
11 #define N 250
12 #define M 102000
13 int a[N],head[N],sum;
14 int cnt,vis[N];
15 int dp[M],dp1[M];
16 int     sum1=0,sum2=0;
17 void init(){
18     cnt  = 0;
19     for(int i =0;i<N;i++) {
20         head[i] = -1;
21         vis[i]  =0;//多组输入
22     }
23 }
24 struct Node{
25     int u,v,nex;
26 }e[N*2];
27 void add(int u,int  v)
28 {
29     e[cnt].u=u;e[cnt].v=v;
30     e[cnt].nex=head[u];head[u]=cnt++;
31 }
32 void dfs(int x,int rt){
33     vis[x] = 1;
34     if(rt==0)
35     sum1+=a[x];
36     else{
37         sum2+=a[x];
38     }
39     for(int i =head[x];i!=-1;i=e[i].nex){
40         int v = e[i].v;
41         if(!vis[v])
42         dfs(v,rt^1);//0^1=1,1^1=0
43     }
44 }
45 int main()
46 {
47     scanf("%d",&t);
48     while(t--)
49     {
50         init();
51         scanf("%d%d",&n,&m);
52         int x,y;
53         sum =0;
54         for(int i =1;i<=n;i++) 
55         {
56             scanf("%d",&a[i]);
57             sum+=a[i]/100;
58             a[i]/=100;//题目说明都是100的倍数
59         }
60         for(int i =0;i<m;i++) {
61             scanf("%d%d",&x,&y);
62             add(x,y);add(y,x);//无向图
63         }
64     
65         int num;
66         for(int i =0;i<=sum;i++) dp[i] = 0;
67         dp[0] = 1;//dp[0]一定先设为1,来引入第一个差值
68         for(int i =1;i<=n;i++) {
69             if(!vis[i]){
70                 sum1=0,sum2=0;
71                 dfs(i,0);
72                 num = abs(sum1-sum2);
73                 //printf("%d %d %d\n",sum1,sum2,num);
74                 for(int j=sum;j>=0;j--){
75                     if(dp[j]){
76                         //如 :0,j. 0 ,num 或者 j,0.0,num
77                         if(abs(j+num)<=sum) dp1[abs(j+num)] =1;
78                         dp1[abs(j-num)]  =1;
79                     }
80                 }
81                 for(int j =sum;j>=0;j--){
82                     dp[j]  = dp1[j],dp1[j] = 0;
83                 }
84             }
85         }
86         //一定需要2个dp 数组,利用dp1一直更新到所有的物品都取完
87         for(int i =0;i<=sum;i++) {
88             if(dp[i]){
89                 
90                 printf("%d\n",(sum+i)/2*100);
91                 break;
92             }
93         }
94     }
95     return 0;
96 }
复制代码

 

posted on   cltt  阅读(248)  评论(0编辑  收藏  举报

编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示