题目:洛谷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; }