题目链接:
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 }
原文地址:https://www.cnblogs.com/letlifestop/p/10935745.html
时间: 2024-10-18 01:13:37