思路:
首先是对题意的分析。
因为它说a要比b多,给你很多这样的条件语句,就想到需要构建图,让小的指向大的,而且按照题意不会出现“环”(不是≥而一定是>),这样就可以用拓扑排序成线性序列,就可以挨个分配钱了。
我想了下,如果条件是“≥”还能不能用拓扑排序,答案应该是不能,因为很可能出现“环”,而拓扑排序的前提就是“无环有向图”,如果有环的话,拓扑排序得到的线性序列是没有涵盖所有点的。因为环上每个点的入度都不为0,并未入队(见图理解),那你那些环上的点与后面其他点的条件也不能得到考虑:
这也就是为什么对于这道题,最后判断合法与否就是看入队的个数是否<总个数n,如果是,则说明无解,该图是有环的,而此题中有环是不允许的,不然不符合现实。
代码:
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e4+5;
const int MAXM=2e4+5;
struct edge
{
int u,v,next;
}e[MAXN];
int p[MAXM];
int vis=0;
int rudu[MAXN];
int money[MAXN];
int n;
void init()
{
memset(p,-1,sizeof(p));
memset(rudu,0,sizeof(rudu));
for(int i=1;i<=n;i++)
money[i]=100;
}
int cnt=1;
void insert(int u,int v)
{
e[cnt].v=v;
e[cnt].next=p[u];
p[u]=cnt;
rudu[v]++;
cnt++;
}
void topo()
{
queue<int> q;
//先将入度为0的结点入队
for(int i=1;i<=n;i++)
{
if(rudu[i]==0)
{
q.push(i);
vis++;
}
}
while(q.empty()==false)
{
int a=q.front();
q.pop();
for(int i=p[a];i!=-1;i=e[i].next)
{
int v=e[i].v;
rudu[v]--;
money[v]=money[a]+1;
if(rudu[v]==0)
{
q.push(v);
vis++;
}
}
}
}
int main()
{
int m;
cin>>n>>m;
init();
while(m--)
{
int a,b;
cin>>a>>b;
insert(b,a);
}
topo();
if(vis<n)
{
cout<<"Unhappy!";
return 0;
}
int ans=0;
for(int i=1;i<=n;i++)
ans+=money[i];
cout<<ans;
return 0;
}