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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章