HDU-5961 传递(暴力)


传递

Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1140    Accepted Submission(s): 514


Problem Description
我们称一个有向图G是 传递的,当且仅当对任意三个不同的顶点a,,若G中有 一条边从a到b且有一条边从b到c ,则G中同样有一条边从a到c。
我们称图G是一个 竞赛图,当且仅当它是一个有向图且它的基图是完全图。换句 话说,将完全图每条边定向将得到一个竞赛图。
下图展示的是一个有4个顶点的竞赛图。

现在,给你两个有向图P = (V, Ep )和Q = (V, Ee ),满足:
1.   EP Ee 没有公共边;
2.  (V, EpEe )是一个竞赛图。
你的任务是:判定是否P,Q同时为传递的。

 

Input
包含至多20组测试数据。
第一行有一个正整数,表示数据的组数。
对于每组数据,第一行有一个正整数n。接下来n行,每行为连续的n个字符,每 个字符只可能是’-’,’P’,’Q’中的一种。
如果第i行的第j个字符为’P’,表示有向图P中有一条边从i到j;
如果第i行的第j个字符为’Q’,表示有向图Q中有一条边从i到j;
否则表示两个图中均没有边从i到j。
保证1 <= n <= 2016,一个测试点中的多组数据中的n的和不超过16000。保证输入的图一定满足给出的限制条件。
 

Output
对每个数据,你需要输出一行。如果P! Q都是传递的,那么请输出’T’。否则, 请输出’N’ (均不包括引号)。
 

Sample Input
      
      
4 4 -PPP --PQ ---Q ---- 4 -P-P --PQ P--Q ---- 4 -PPP --QQ ---- --Q- 4 -PPP --PQ ---- --Q-
 

Sample Output
      
      
T N T N
Hint
在下面的示意图中,左图为图为Q。
注:在样例2中,P不是传递的。在样例4中,Q不是传递的。
题解:暴力

如果u是v的父节点,v是w的父节点,那么u一定也是w的父节点,用bitset记录每个点的父节点有哪些,跑一遍spfa,最后枚举每个点的父节点看是否与父节点连上了一条边


#include<bits/stdc++.h>
using namespace std;
const int MX = 2020;
char mp[MX][MX];
bitset<MX>b[MX];
struct Edge {
    int v, nxt;
} E[MX*MX], edge[MX*MX];
int head[MX], Head[MX], tot, rear, n;
int p[MX], p1[MX], p2[MX], vis[MX];
void init() {
    memset(head, -1, sizeof(head));
    memset(Head, -1, sizeof(Head));
    for (int i = 0; i < n; i++) p1[i] = p2[i] = i;
    tot = rear = 0;
}
void ADD(int u, int v) {
    E[tot].v = v;
    E[tot].nxt = Head[u];
    Head[u] = tot++;
}
void add(int u, int v) {
    edge[rear].v = v;
    edge[rear].nxt = head[u];
    head[u] = rear++;
}
int find(int x) {
    return p[x] == x ? x : (p[x] = find(p[x]));
}
int find1(int x) {
    return p1[x] == x ? x : (p1[x] = find1(p1[x]));
}
int find2(int x) {
    return p2[x] == x ? x : (p2[x] = find2(p2[x]));
}
bool solve(Edge E[], int head[], int px[], char op) {
    for (int i = 0; i < n; i++) {
        b[i].reset();
        b[i][i]=1;
        vis[i] = 0;
        p[i] = px[i];
    }
    queue<int>q;
    for (int i = 0; i < n; i++) if (find(i) == i) {
        q.push(i); vis[i] = 1;
    }
    while (!q.empty()) {
        int u = q.front(); q.pop();
        vis[u] = 0;
        for (int i = head[u]; ~i; i = E[i].nxt) {
            int v = E[i].v;
            if ((b[v] | b[u]) != b[v]) {
                b[v] |= b[u];
                if (!vis[v]) {
                    q.push(v);
                    vis[v] = 1;
                }
            }
        }
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (i == j) continue;
            if (b[i][j] && mp[j][i] != op) return false;
        }
    }
    return true;
}
int main() {
    int T;
    //freopen("in.txt","r",stdin);
    scanf("%d", &T);
    while (T--) {
        scanf("%d", &n);
        init();
        for (int i = 0; i < n; i++) scanf("%s", &mp[i]);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (mp[i][j] == 'P') {
                    ADD(i, j);
                    int pi = find1(i), pj = find1(j);
                    if (pi != pj) p1[pj] = pi;
                }
                if (mp[i][j] == 'Q') {
                    add(i, j);
                    int pi = find2(i), pj = find2(j);
                    if (pi != pj) p2[pj] = pi;
                }
            }
        }
        if (solve(E, Head, p1, 'P') && solve(edge, head, p2, 'Q')) printf("T\n");
        else printf("N\n");
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值