首页 > 代码库 > ZOJ 3780 E - Paint the Grid Again 拓扑排序

ZOJ 3780 E - Paint the Grid Again 拓扑排序

https://vjudge.net/problem/49919/origin

题意:给你n*n只出现O和X的字符阵。有两种操作,一种操作Ri将i全变成X,一种操作Ci将i全变成O,每个不同的操作最多进行一次。现给出目标状态,求空盘下的字典序最小的操作顺序是怎样的。

思路:拿到题目看起来很复杂,但仔细读题会发现X和O只由特定操作出现,且操作只进行一次,那么单独地考虑每行每列,如i行中出现了O,且存在X(如果不存在X那么可以略去Ri操作),说明在Ri操作后进行了Cj的操作,同样的方法去考虑列,就能得到所有需要进行的行列操作相对顺序。这显然是个拓扑结构。那么将行操作或列操作看作点,建图拓扑排序即可。

关键还是在于建模,vijos上有道很相像的题目(1030),但比这道复杂一些还需要DFS。但是这道省赛题由于要求的复杂度不太严格,还可以模拟做。

但我居然一下子没有想出来用拓扑排序orz

weak-dish?

/** @Date    : 2017-03-27-21.44  * @Author  : Lweleth (SoungEarlf@gmail.com)  * @Link    : https://github.com/  * @Version :  */#include<bits/stdc++.h>#define LL long long#define PII pair#define MP(x, y) make_pair((x),(y))#define fi first#define se second#define PB(x) push_back((x))#define MMG(x) memset((x), -1,sizeof(x))#define MMF(x) memset((x),0,sizeof(x))#define MMI(x) memset((x), INF, sizeof(x))using namespace std;const int INF = 0x3f3f3f3f;const int N = 1e5+20;const double eps = 1e-8;const int ost = 510;char mp[510][510];vectorvt[1100];int fr[510], fc[510];int cnt[1100];int n;void init(){    MMF(fr);    MMF(fc);    MMF(cnt);    for(int i = 0; i < n + ost; i++)        vt[i].clear();    for(int i = 0; i < n; i++)    {        for(int j = 0; j < n; j++)        {            if(mp[i][j] == ‘O‘)                fc[j] = 1;            else fr[i] = 1;        }    }    for(int i = 0; i < n; i++)    {        if(!fr[i]) continue;        for(int j = 0; j < n; j++)        {            if(mp[i][j] == ‘O‘)                vt[i].PB(j + ost), cnt[j + ost]++;        }    }    for(int j = 0; j < n; j++)    {        if(!fc[j]) continue;        for(int i = 0; i < n; i++)        {            if(mp[i][j] == ‘X‘)                vt[j + ost].PB(i), cnt[i]++;        }    }}void top(){    int ct = 0;    priority_queue<int, vector, greater >q;    for(int i = 0; i < n + ost; i++)    {        if(cnt[i] == 0 && vt[i].size() != 0)            q.push(i);    }    while(!q.empty())    {        int nw = q.top();        q.pop();        for(int i = 0; i < vt[nw].size(); i++)        {            int nt = vt[nw][i];            cnt[nt]--;            if(!cnt[nt])                q.push(nt);        }        if(nw < ost)            printf("%sR%d", ct==0?"":" ", nw + 1), ct = 1;        else printf("%sC%d", ct==0?"":" ", nw - ost + 1), ct = 1;    }    if(ct == 0)        printf("No solution");    printf("\n");}int main(){    int T;    cin >> T;    while(T--)    {        cin >> n;        for(int i = 0; i < n; i++)        {            scanf("%s", mp[i]);        }        init();        top();    }    return 0;}

ZOJ 3780 E - Paint the Grid Again 拓扑排序