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

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


你可能感兴趣的:(UVa-10618 Tango Tango Insurrection&& UVa-1627 Team them up!)