题目:洛谷P1038、Vijos P1105、codevs1088。
题目大意:给你一个有向图,每个非源点i的值的计算方式为$C_i=sumlimits_{(j,i)in E}W_{ji}C_j-U_i$,求每个汇点(没有出边的点)的值C。
解题思路:首先一遍DFS找出所有汇点,然后BFS计算即可。注意源点不需要减去U。
C++ Code:
#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
int n,w[222][222],p;
struct sj{
int c,u;
}a[222];
vector<int>In,Out;
bool vis[222];
queue<int>q;
void dfs(int t){
vis[t]=true;
bool hasnxt=false;
for(int i=1;i<=n;++i)
if(w[t][i]){
hasnxt=true;
if(!vis[i])dfs(i);
}
if(!hasnxt)Out.push_back(t);
}
void bfs(){
memset(vis,0,sizeof(vis));
for(int i=0;i<In.size();++i){
q.push(In[i]);
vis[In[i]]=true;
}
while(!q.empty()){
int u=q.front();
q.pop();
bool b=true;
a[u].c-=a[u].u;
if(a[u].c>0)
for(int v=1;v<=n;++v)
if(w[u][v]){
a[v].c+=w[u][v]*a[u].c;
if(!vis[v]){
vis[v]=true;
q.push(v);
}
}
}
}
int main(){
scanf("%d%d",&n,&p);
for(int i=1;i<=n;++i){
scanf("%d%d",&a[i].c,&a[i].u);
if(a[i].c)In.push_back(i);
}
memset(w,0,sizeof w);
while(p--){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
w[x][y]=z;
}
memset(vis,0,sizeof vis);
for(int i=0;i<In.size();++i)dfs(In[i]);
for(int i=0;i<In.size();++i)a[In[i]].u=0;
bfs();
bool hasans=false;
sort(Out.begin(),Out.end());
for(int i=0;i<Out.size();++i)
if(a[Out[i]].c>0){
hasans=true;
printf("%d %d
",Out[i],a[Out[i]].c);
}
if(!hasans)puts("NULL");
return 0;
}