弄了一整晚 各种bug ...最后超时,差点放弃... 然后...没指望地 随意剪了个枝.,然后......居然做出来了...
题目大意:有k个箱子(1<=k<=15),在第i个箱子里有ni(1<=n<=5000)个整数 ( |aij|<=1e9)。所有整数都是不同的。对 每个箱子 都 进行这样的操作:从每个箱子中取出一个整数,并放入 另一个或原本的 箱子中。问能否进行这样子的操作使得 操作结束后,每个箱子的数字的和相等。
赛后补题,看了codeforces的标签:
Problem tags:bitmasks,dfs and similar,dp,graphs,implementation。
dp实在太弱,不懂该怎么做,相信dp的做法会简单很多,然而我不会。
我是从graph的思想,用dfs的方法通过bitmasks记录状态来做的....
具体:
在最开始,计算sum和aver(平均值) sum模n有余则 直接输出no
注意题目的一句话:All of the integers are distinct.
所以就是 从每个box里取一个数出来,那么重新放回去的数值aij 的 i 和j 是唯一确定的。
所以对所有box里的所有数值 它 至多有 一个相对应的数值aij , 如果假想以有向边连接这样的对应关系,那么
正解必是 从1到n 覆盖了所有的数值的 1个或多个不相交环
环里边的顶点对应的是box的标号。
所以 做法是:
对于所有box的每个点,dfs去找它所在的环,并把 环 存进 环所覆盖的box标号的 容器里。
环用二进制状压去记录。
因为每个点题目保证了只有1条出边,所以,找到环的点在之后就不用再进行判断和查找。
之后就是搜索,判断有没有1个或多个环 或起来 的值 恰好是 n个1的二进制状态。有的话就是答案,找不到就是no。
然后是,适当剪枝。
#include<bits/stdc++.h> #define debug printf("!"); #define mp make_pair using namespace std; typedef long long ll; const int maxn=5e3+50; const int inf=0x3f3f3f3f; int n,allstate; ll a[16][maxn],sum,aver; unordered_map<ll,pair<int,int>>mpp; //tsum-tval+val=aver struct P{ int sta,id; }; vector<P>vec[16]; bool vis[16][maxn]; bool dfs(int idi,int idj,int&sta,int sti,int stj)//找通过st的回路 { int num=a[idi][0]; ll tsum=a[idi][num+1],val,tval=a[idi][idj]; val=aver-tsum+tval; if(!mpp.count(val))return 0; pair<int,int>pa=mpp[val]; if(vis[pa.first][pa.second])return 0; //所要访问的点有回路 这条回路不属于自己 并且 无法通过这个点找到新的回路 所以直接return false if(pa.first==idi&&pa.second!=idj)return 0; //在题意中 当前点要从box拿出去 然后将pa这个点放进来 可以是拿出去放进来同一个点 或者来自不同box的两个点 但不可能是来自同一box的不同点 if(pa.first==sti&&pa.second==stj) { vis[idi][idj]=1;//找到回路 标记点 此后这个点不用再找回路了 因为1个点最多只有一条回路 //因为 一个点所连的点是一个数值 题目原话:All of the integers are distinct. vec[idi].push_back(P{sta,idj}); return 1; } if((1<<pa.first)&sta)return 0; //这个点所连的点在回路中存在 则这个sta是错的 不是单纯的回路 sta|=(1<<pa.first); if(dfs(pa.first,pa.second,sta,sti,stj)) { vis[idi][idj]=1; vec[idi].push_back(P{sta,idj}); return 1; } return 0; } int ans[16];//ans[i]=j 把i集合中的j拿出去换 bool can[16][maxn]; bool cann[140000][15]; bool search(int sta) { if(!sta)return 1; for(int i=1;i<=n;i++) { if((1<<i)&sta&&!cann[sta][i]) { for(int j=0;j<vec[i].size();j++) { if(can[i][j])continue; if((sta&vec[i][j].sta)==vec[i][j].sta) { if(search(sta-vec[i][j].sta)) { ans[i]=vec[i][j].id; return 1; } } if(sta==allstate)can[i][j]=1; } } cann[sta][i]=1; } return 0; } int tans[16]; void last(int idi,int idj)//根据之前记录的状态记下答案 { int num=a[idi][0]; ll tsum=a[idi][num+1],val,tval=a[idi][idj]; val=aver-tsum+tval; pair<int,int> p=mpp[val]; tans[p.first]=idi; if(ans[p.first]!=inf)return; ans[p.first]=p.second; last(p.first,p.second); } int main() { int i,j,sta; ll tsum; scanf("%d",&n); for(i=1;i<=n;i++) { allstate|=1<<i; scanf("%lld",&a[i][0]); for(j=1,tsum=0;j<=a[i][0];j++) { scanf("%lld",&a[i][j]); tsum+=a[i][j]; mpp[a[i][j]]=mp(i,j); } sum+=tsum; a[i][j]=tsum; } if(sum%n) { puts("No");return 0; } aver=sum/n; for(i=1;i<=n;i++) for(j=1;j<=a[i][0];j++) if(!vis[i][j]) dfs(i,j,sta=1<<i,i,j); for(i=1;i<=n;i++) if(!vec[i].size()) { puts("No");return 0; } memset(ans,inf,sizeof(ans)); if(search(allstate)) { puts("Yes"); for(i=1;i<=n;i++) if(ans[i]!=inf)last(i,ans[i]); for(i=1;i<=n;i++) printf("%lld %d\n",a[i][ans[i]],tans[i]); } else puts("No"); }
原文地址:https://www.cnblogs.com/kkkek/p/11824202.html