题目链接:点击打开链接
题意描述:在一个公司中,老板打算给员工发奖励,每个员工至少发888,但是员工之间奖励需要满足一些条件,如 a b代表a的奖励要比b至少多1,现在给定n个员工,和m的条件,问老板能否满足员工的要求(可能存在a比b多,同时b又比a多,此时无法满足),如果能够满足,老板至少需要准备多少?
解题思路:
1、我们可以根据条件建图,如果a比b多,则建一条b->a的有向边
2、判断有向图中是否存在回路,如果存在回路则无法满足要求(注意:图不保证是联通的,可能存在好多个联通块)
3、如果满足要求,我们可以把入度为0的点加入队列中,然后更新其他点
代码:
#pragma comment(linker,"/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <queue>
#define MAXN 10010
#define MAXE 20010
#define INF 0x7fffffff
using namespace std;
int head[MAXN];
struct Edge{
int to,_next;
}edge[MAXE*2];
int tol;
void init(){
tol=0; memset(head,-1,sizeof(head));
}
void addEdge(int from,int to){
edge[tol].to=to;edge[tol]._next=head[from];head[from]=tol++;
}
int n,m;
int inn[MAXN],dis[MAXN];
bool vis[MAXN];
bool dfs(int s){
for(int i=head[s];i!=-1;i=edge[i]._next){
int to=edge[i].to;
if(vis[to]) return true;
else{
vis[to]=true;
if(dfs(to)) return true;
vis[to]=false;
}
}
return false;
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
if(n==0) {printf("0\n");continue;}
init();
memset(inn,0,sizeof(inn));
int from,to;
bool flag=false;
for(int i=1;i<=m;++i){
scanf("%d%d",&to,&from);
if(from==to) flag=true;
addEdge(from,to);
inn[to]++;
}
if(flag) {printf("-1\n");continue;}
for(int i=1;i<=n;++i) dis[i]=0;
queue<int> q; while(!q.empty()) q.pop();
int i;
//flag=false;
for(i=1;i<=n;++i){
// if(inn[i]) continue;///注意,忽悠了连个联通块的情况,如一个孤立点和一个环的情况
//else flag=true;
memset(vis,false,sizeof(vis));
vis[i]=true;
if(dfs(i)) break;
dis[i]=0;
q.push(i);
}
if(i<=n){ printf("-1\n");continue; }
while(!q.empty()){
int t=q.front(); q.pop();
for(int i=head[t];i!=-1;i=edge[i]._next){
int to=edge[i].to;
if(dis[to]<dis[t]+1){
dis[to]=dis[t]+1;
q.push(to);
}
}
}
int ans=0;
for(int i=1;i<=n;++i)
ans+=dis[i];
printf("%d\n",ans+n*888);
}
return 0;
}