第十二届湖南省大学生计算机程序设计竞赛(热身赛)

E  题:小X的战斗力(SFPA) 

TimeLimit:1SecMemoryLimit:128MB 

Submit:18Solved:6 

[Submit][Status][WebBoard] 

Description 

  • 小X才不是战五渣!为了证明这一点,小X进行了一些调查。

    小X收集了班上一些同学之间决斗的胜负情况。决斗是两个人之间实力的比拼,实力用战斗力来衡量。小X猜想,战斗力高的人一定会在决斗中取得胜利。决斗一定会分出胜负,因此不存在战斗力相同的两人。

    小X在调查分析自己的实力排名的同时,也顺便知道了其他一些同学的战斗力排名情况。现在你获取了这一批数据,请求出小X的调查结果。

    因为小X并不怎么记得班上同学的名字,于是在数据中用数字来给同学们编号,从 1  N 

    小X把自己标为 1  号。

Input 

  • 第一行为数据组数 TT<=10 

    对于每组数据:

    第一行为两个整数 N  M1<=N<=1501<=M<=5000  N  表示小X 班上同学的总人数, M  表示小X 收集了 M  次决斗的信息。

    接下来M 行,每行两个整数 AB1<=A,B<=N,AB  ,描述了一次决斗,决斗的结果是同学A胜出。

Output 

  • 对于每组数据:

    如果小X的猜想没错,输出两行。第一行,如果可以确定小X的排名则输出一个整数 P  表示小X的排名,否则输出1 ;第二行,输出一个整数 K  表示可以确定具体名次的班上同学的数量(包括小X自己)。

    如果小X的猜想有误,输出一行一个字符串Wrong ,没有引号。


SampleInput 
2
5 5
4 3
4 2
3 2
1 2
2 5
3 3
1 2
2 3
3 1
SampleOutput 
-1
2
Wrong

HINT 
对于第一组数据,可以确定名次的同学有 2  个,2 号第 4  5 号第 5 


题意

给你一定的排名关系,让你求出其中多少个顶点的排名已经固定,以及第一个人即小X的在排名中结果是多少?

解题思路

对于给定的N 个点,针对每一个顶点 v  ,我们求出排名一定在他前面的人的个数cnt1[v] ,然后再求出排名一定在他后面的人的个数 cnt2[v]  ,然后将这两个数据相加得到 cnt[v]  ,如果 cnt[v]=N1  ,那么就一定是固定好排名的,反之则排名不固定,使用 SFPA  算法可以直接处理处这些数据而且速度比 Floyd  算法快。

代码

时间复杂度: O(|V| 2 ) 

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <vector>
#include <cctype>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iomanip>
#include <typeinfo>
#include <iostream>
#include <algorithm>
#include <functional>


using namespace std;

const int MAXN = 1e5 + 5;
const int MAXM = 1e5 + 5;

int V,E;
bool succ;


struct Edge {
    int u, v, next;
} G[MAXN];

struct o {
    int x, y;
} O[MAXN];


int head[MAXN], e;
bool vis[MAXN];
int cnt[MAXN];


void add(int u,int v) {
    G[e].u = u;
    G[e].v = v;
    G[e].next = head[u];
    head[u] = e ++;
}
void SPFA(int s) {
    queue<int>que;
    for(int i = 1; i <= V; i ++) {
        vis[i] = false;
    }
    vis[s] = true;
    que.push(s);
    while(!que.empty()) {
        int temp = que.front();
        que.pop();
        for(int i = head[temp]; i != -1; i = G[i].next) {
            int v = G[i].v;
            if(!vis[v]) {
                cnt[s] ++;
                vis[v] = true;
                que.push(v);
            }
            if(v == s) {
                succ = false;
            }
        }
    }
}
int main() {
    int T;
    scanf("%d", &T);
    while(T --) {
        succ = true;
        scanf("%d%d",&V,&E);
        memset(head, -1, sizeof(head));
        memset(cnt, 0, sizeof(cnt));
        e = 0;
        for(int i = 1; i <= E; i ++) {
            scanf("%d%d",&O[i].x, &O[i].y);
            add(O[i].x, O[i].y);
        }
        for(int i = 1; i <= V; i ++) {
            SPFA(i);
        }
        int rkx = V - cnt[1];
        memset(head, -1, sizeof(head));
        e = 0;
        for(int i = 1; i <= E; i ++) {
            add(O[i].y, O[i].x);
        }

        for(int i = 1; i <= V; i ++) {
            SPFA(i);
        }

        int ans = 0;
        for(int i = 1; i <= V; i ++) {
            if(cnt[i] == V - 1) {
                ans ++;
            } else {
                if(i == 1) rkx = -1;
            }
        }
        if(!succ) {
            puts("Wrong");
        } else {
            printf("%d\n%d\n",rkx, ans);
        }

    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值