10618
题意繁复,见紫书P291
本题条件比较复杂,是情况比较多的多维dp,个人认为难点在处理各阶段关系上。
看了紫书详细的解释,将各状态下的决策结果通过构造函数计算出来即可。记录一下,以后温习直接翻书。
#include <algorithm> #include <iostream> #include <sstream> #include <cstring> #include <cstdlib> #include <string> #include <vector> #include <cstdio> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> using namespace std; #define INF 0x3f3f3f3f const int N=100005; const int mod=1e9+7; const int UP=0; const int LEFT=1; const int RIGHT=2; const int DOWN=3; int action[75][4][4][3],d[75][4][4][3]; char seq[75],pos[256],footch[]=".LR"; int energy(int a,int b) { if (a==b) { return 3; } if (a+b==3) { return 7; } return 5; } int energy(int i,int a,int b,int s,int f,int t,int& ta,int &tb) { ta=a;tb=b; if (f==1) { ta=t; } else if (f==2) tb=t; if (ta==tb) return -1; if (ta==RIGHT&&tb==LEFT) return -1; if (a==RIGHT&&tb!=b) return -1; if (b==LEFT&&ta!=a) return -1; int e; if (f==0) e=0; else if (f!=s) e=1; else { if (f==1) e=energy(a, ta); else e=energy(b, tb); } return e; } void update(int i,int a,int b,int s,int f,int t) { int ta,tb; int e=energy(i,a,b,s,f,t,ta,tb); if (e<0) return; int cost=d[i+1][ta][tb][f]+e; int& ans=d[i][a][b][s]; if (cost<ans) { ans=cost; action[i][a][b][s]=f*4+t; } } int main() { pos['U']=0;pos['L']=1; pos['R']=2;pos['D']=3; while (scanf("%s",seq)==1) { if (seq[0]=='#') break; int n=strlen(seq); memset(d, 0, sizeof(d)); for (int i=n-1; i>=0; i--) for (int a=0; a<4; a++) for (int b=0; b<4; b++) if (a!=b) for (int s=0; s<3; s++) { d[i][a][b][s]=10*n; if (seq[i]=='.') { update(i,a,b,s,0,0); for (int t=0; t<4; t++) { update(i,a,b,s,1,t); update(i,a,b,s,2,t); } } else { update(i,a,b,s,1,pos[seq[i]]); update(i,a,b,s,2,pos[seq[i]]); } } int a=LEFT,b=RIGHT,s=0; for (int i=0; i<n; i++) { int f=action[i][a][b][s]/4; int t=action[i][a][b][s]%4; printf("%c",footch[f]); s=f; if (f==1) a=t; else if (f==2) b=t; } cout<<endl; } return 0; }1627
题意:
有n个人,把他们分成非空的两组,使得每个人都被分到一组,且同组中的人互相认识。要求两组的成员人数尽量接近。多解时输出任意方案,无解时输出No Solution。
分析:
自己没想到什么方法,紫书说要点是0-1背包。即对每个人的情况进行处理,假设a在组0,那么与a不是相互认识关系的人必须在组1,同理,与a不是相互认识的关系的人群为b,则与b不是相互关系的就必须在0。
按此情况判断是否合理,若合理,则存在解决方案。
通过dp对组1和组0之间的差值进行判断,对可能出现的差值进行标记。最后从小到大找寻最小差值即可,通过栈记录如何分组,最后输出。代码细节很多,很值得学习。
#include <algorithm> #include <iostream> #include <sstream> #include <cstring> #include <cstdlib> #include <string> #include <vector> #include <cstdio> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> using namespace std; #define INF 0x3f3f3f3f const int N=100005; const int mod=1e9+7; int n,g[105][105],color[105],diff[105],cc; vector<int> team[105][2]; bool dfs(int u,int c) { color[u]=c; team[cc][c-1].push_back(u); for (int v=0; v<n; v++) { if (u!=v&&!(g[u][v]&&g[v][u])) { if (color[v]>0&&color[v]==color[u]) return false; if (!color[v]&&!dfs(v,3-c)) return false; } } return true; } bool build_graph() { memset(color, 0, sizeof(color)); cc=0; for (int i=0; i<n; i++) { if (!color[i]) { team[cc][0].clear(); team[cc][1].clear(); if (!dfs(i, 1)) return false; diff[cc]=team[cc][0].size()-team[cc][1].size(); cc++; } } return true; } int d[105][2*105],teamno[105]; void print(int ans) { vector<int> team1,team2; for (int i=cc-1; i>=0; i--) { int t; if (d[i][ans-diff[i]+n]) { t=0; ans-=diff[i]; } else { t=1; ans+=diff[i]; } for (int j=0; j<team[i][t].size(); j++) { team1.push_back(team[i][t][j]); } for (int j=0; j<team[i][1^t].size(); j++) { team2.push_back(team[i][1^t][j]); } } printf("%d",team1.size()); for (int i=0; i<team1.size(); i++) { printf(" %d",team1[i]+1); } cout<<endl; printf("%d",team2.size()); for (int i=0; i<team2.size(); i++) { printf(" %d",team2[i]+1); } cout<<endl; } void dp() { memset(d, 0, sizeof(d)); d[0][0+n]=1; for (int i=0; i<cc; i++) { for (int j=-n; j<=n; j++) { if (d[i][j+n]) { d[i+1][j+diff[i]+n]=1; d[i+1][j-diff[i]+n]=1; } } } for (int ans=0; ans<=n; ans++) { if (d[cc][ans+n]) { print(ans); return; } if (d[cc][-ans+n]) { print(-ans); return; } } } int main() { int t,temp; cin>>t; while (t--) { cin>>n; memset(g, 0, sizeof(g)); for (int i=0; i<n; i++) { while (1) { scanf("%d",&temp); if (temp==0) break; g[i][temp-1]=1; } } if (n==1||!build_graph()) { cout<<"No solution\n"; } else dp(); if (t) { cout<<endl; } } return 0; }