Miku and Generals(可行性背包) 西安邀请赛

 题目链接:

https://nanti.jisuanke.com/t/39271

 题目大意:

当前有两个人,然后有n个点,每个点都有权值。然后给你m个对应关系,每一次的对应关系给你两个数,t1 和 t2 ,代表这两个不能在一个人手里。然后让你分配这n个点,使得这两个人的

差距进尽可能的小。然后输出大的那个。

具体思路:

对于每一个联通图,我们二分图染色,dp[i]表示当前这个差值能不能到达,这个过程可以通过可行性背包来解决。然后找一个最小的差值就可以了。

AC代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 # define ll long long
 4 # define inf 0x3f3f3f3f
 5 const int maxn = 2e5+100;
 6 int a[maxn];
 7 vector<int>Edge[maxn];
 8 int vis[maxn];
 9 int sum_0,sum_1;
10 void dfs(int u,int type){
11 if(!type)sum_0+=a[u];
12 else sum_1+=a[u];
13 vis[u]=1;
14 for(int i=0;i<Edge[u].size();i++){
15 int to=Edge[u][i];
16 if(vis[to])continue;
17 dfs(to,type^1);
18 }
19 }
20 int dp[maxn],pre[maxn];
21 int main(){
22 int T;
23 scanf("%d",&T);
24 while(T--){
25 int n,m,sum=0;
26 scanf("%d %d",&n,&m);
27 for(int i=0;i<=n;i++){vis[i]=0;Edge[i].clear();}
28 for(int i=1;i<=n;i++){
29 scanf("%d",&a[i]);
30 a[i]/=100;
31 sum+=a[i];
32 }
33 for(int i=0;i<=sum;i++){dp[i]=0;pre[i]=0;}
34 int st,ed;
35 for(int i=1;i<=m;i++){
36 scanf("%d %d",&st,&ed);
37 Edge[st].push_back(ed);
38 Edge[ed].push_back(st);
39 }
40 dp[0]=1;
41 for(int i=1;i<=n;i++){
42 if(vis[i])continue;
43 sum_0=0,sum_1=0;
44 dfs(i,0);
45 int tmp=abs(sum_0-sum_1);
46 for(int j=0;j<=sum;j++){
47 if(!dp[j])continue;
48 if(j+tmp<=sum)pre[j+tmp]=1;
49 if(abs(j-tmp)>=0)pre[abs(j-tmp)]=1;
50 }
51 for(int j=0;j<=sum;j++){
52 dp[j]=pre[j];
53 pre[j]=0;
54 }
55 }
56 for(int i=0;i<=sum;i++){
57 if(!dp[i])continue;
58 printf("%d\n",(i+sum+1)/2*100);
59 break;
60 }
61 }
62 return 0;
63 }

 

posted @ 2019-05-28 10:41  Let_Life_Stop  阅读(486)  评论(0编辑  收藏  举报