UVa-10618 Tango Tango Insurrection&& UVa-1627 Team them up!

来源:互联网 发布:网络情歌对唱大全 编辑:程序博客网 时间:2024/05/22 15:43

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


0 0