题目
题意
有 k k k个box,每个box放了 x i x_i xi个整数(所有数distinct)。可以操作一次:从每个box拿出一个数,然后打乱再放回每个box一个数,问是否可以使得每个box数的和相同,并输出路径。(k<15)
思路
考虑建图:
对于每一个物品
a
i
j
a_{ij}
aij,考虑将他拿出来,必然有另一个物品
a
k
,
z
a_{k,z}
ak,z放回这个物品所在的box。
如果
a
k
,
z
a_{k,z}
ak,z合理,那么就从
a
i
j
a_{ij}
aij向
a
k
,
z
a_{k,z}
ak,z引出一条有向边。
然后问题就转换为是否可以找出一个或多个环,使得每个数出现一次。
考虑求出所有环:
可以发现,每个点最多一个出边,那么暴力遍历每一个点,每个点最多dfs 15次。就可以求出所有的环。
考虑状压dp:
d
p
[
i
]
:
i
dp[i]:i
dp[i]:i状态是否存在,
d
p
[
i
]
dp[i]
dp[i]可以通过
d
p
[
j
]
dp[j]
dp[j]增加一个环转移过来。那么就需要枚举子集。
考虑输出路径:
dp倒着转移回去,并把每个环暴力dfs。
这里有个很坑的爆int:map查询的时候,传进的参数爆int。
代码映射写的比较丑。。。。。
/*
Author: Rshs
Time: 2019-11-09-14.35
*/
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const double pai = acos(-1);
const double eps = 1e-8;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
map<LL,PII>binid;
map<int,int>id3;
vector<int>a[20],g[MXN];
int st[MXN],id1[MXN],id2[MXN];
int dp[(1<<16)];
int ok[(1<<16)];
int ff[(1<<16)];
int in[20];
int main(){
//cout<<-6%2;
int k;cin>>k;
LL sum=0;
for(int i=1;i<=k;i++){
int cc;scanf("%d",&cc);
st[i+1]=st[i]+cc;
for(int j=1;j<=cc;j++) {
int sa;scanf("%d",&sa);a[i].push_back(sa);
id1[st[i]+j]=i;id2[st[i]+j]=sa;id3[sa]=i;
binid[sa]=MP(i,j);sum+=(LL)sa;
}
}
if(sum%k!=0) return puts("No"),0;
LL ave=sum/k;
for(int i=1;i<=k;i++){
LL ss=0;
for(auto j:a[i]){
ss+=(LL)j;
}
LL xx=ave-ss;
for(int j=0;j<SZ(a[i]);j++){
LL need=xx+(LL)a[i][j];
//if(need<0) continue;
if(need==a[i][j]) {g[st[i]+j+1].push_back(st[i]+j+1);continue;}
if(binid.find(need)==binid.end()) continue;
PII zz=binid[need];
if(zz.FI!=i)
g[st[i]+j+1].push_back(st[zz.FI]+zz.SE);
}
}
for(int i=1;i<=st[k]+SZ(a[k]);i++){
int S=0,now=i;set<int>v;
while(1){
if(SZ(g[now])==0) break;
if(v.find(now)!=v.end()){
if(now==i) ok[S]=1,ff[S]=i;
break;
}
S=S+(1<<(id1[now]));
v.insert(now);
now=g[now][0];
}
}
dp[0]=1;
for(int i=1;i<(1<<(k+1))-1;i++){
for(int S=i;S!=0;S=(S-1)&i){
if(dp[i-S]&&ok[S]) {dp[i]=1;break;}
}
}
int now=(1<<(k+1))-2;
if(dp[now]==0) return puts("No"),0;
puts("Yes");
while(1){
if(now==0) break;
for(int S=now;S!=0;S=(S-1)&now){
if(ok[S]&&dp[now-S]){
now=now-S;
int cur=g[ff[S]][0];
in[id1[ff[S]]]=id2[cur];
while(cur!=ff[S]){
in[id1[cur]]=id2[g[cur][0]];
cur=g[cur][0];
}
break;
}
}
}
vector< pair<int,pair<int,int > > >ans;
for(int i=1;i<=k;i++){
ans.push_back(MP(id3[in[i]],MP(in[i],i)));
}
sort(ans.begin(),ans.end());
for(auto i:ans) cout<<i.SE.FI<<' '<<i.SE.SE<<'\n';
return 0;
}