先判一下能不能均分,不能就gg,否则设平均数为\(ave\),第\(i\)个盒子中的数的和为\(sum_i\)
然后考虑枚举一个盒子中扔掉一个数\(x\),那么由于所有数两两不同,那么可以找到一个唯一的\(y\)扔进这个盒子,使其等于\(ave\)
这里显然可以通过\(sum_i+y-x=ave\)反解出\(y=ave+x-sum_i\)
这样不停的找前驱,就是一个找环的过程
然后如果一个环能闭上,那么就是一个合法的集合
对于集合之间,最后做一次子集DP就行了
输出方案的话记一下DP的前驱状态和每个合法集合的构成即可
复杂度\(O(k^2n+3^k)\)
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 int k; 5 ll s,sum[16]; 6 vector<ll> a[16]; 7 unordered_map<ll,int> has[16]; 8 bool vis[16]; 9 bool iscir[40005],dp[40005]; 10 int pp[40005]; 11 struct Node 12 { 13 int from,to; 14 ll val; 15 Node(int F=0,int T=0,ll V=0){from=F;to=T;val=V;} 16 }; 17 bool operator < (Node A,Node B){return A.from<B.from;} 18 vector<Node> Ans[40005]; 19 void go(int pos,ll val) 20 { 21 memset(vis,0,sizeof(vis)); 22 int u=pos; 23 ll w=s+val-sum[u]; 24 vector<Node> tmp;tmp.clear(); 25 while(1) 26 { 27 int pre=-1; 28 for(int i=0;i<k;++i)if(has[i][w]){pre=i;break;} 29 if(pre==-1)return; 30 tmp.push_back(Node(pre,u,w)); 31 u=pre; 32 if(vis[u])return; 33 vis[u]=1; 34 if(u==pos)break; 35 w=s+w-sum[u]; 36 } 37 if(val!=w)return; 38 int S=0; 39 for(int i=0;i<k;++i)if(vis[i])S|=(1<<i); 40 iscir[S]=1; 41 Ans[S]=tmp; 42 } 43 vector<Node> res; 44 void print(int S) 45 { 46 if(!S)return; 47 for(Node u:Ans[S^pp[S]])res.push_back(u); 48 print(pp[S]); 49 } 50 int main() 51 { 52 scanf("%d",&k); 53 s=0; 54 for(int sz,i=0;i<k;++i) 55 { 56 scanf("%d",&sz); 57 while(sz--) 58 { 59 ll x;scanf("%I64d",&x); 60 a[i].push_back(x); 61 has[i][x]=1; 62 sum[i]+=x; 63 } 64 s+=sum[i]; 65 } 66 if(s%k)puts("No"); 67 else 68 { 69 s/=k; 70 for(int i=0;i<k;++i) 71 for(ll x:a[i])go(i,x); 72 dp[0]=1; 73 for(int S=1;S<(1<<k);++S) 74 { 75 for(int s=S;s;s=(s-1)&S)if(dp[S^s]&iscir[s]) 76 { 77 dp[S]=1; 78 pp[S]=S^s; 79 } 80 } 81 if(!dp[(1<<k)-1])puts("No"); 82 else 83 { 84 puts("Yes"); 85 res.clear(); 86 print((1<<k)-1); 87 sort(res.begin(),res.end()); 88 for(Node u:res)printf("%I64d %d\n",u.val,u.to+1); 89 } 90 } 91 }
原文:https://www.cnblogs.com/uuzlove/p/12310237.html