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;
}