题意:
给定一个有向图,每条边都有一个权值,每次你可以选择一个结点和一个整数的,把所有以v为终点的边的权值减去d,
把所有以v为起点的边的权值加上d
最后要让所有边的权的最小值非负且尽量大
代码
#include<stdio.h> #include<iostream> #include<algorithm> #include<cstring> #include<vector> #include<queue> using namespace std; const int N = 1e3; const int inf = 0x3f3f3f3f; int dist[N],inq[N],cnt[N]; struct node { int v,w; node(int v,int w):v(v),w(w) {}; }; vector<node> G[N]; void init(int n) { for(int i = 0; i<=n; i++) G[i].clear(); } bool spfa(int n) { queue<int> q; q.push(0); memset(inq,0,sizeof(inq)); memset(cnt,0,sizeof(cnt)); memset(dist,inf,sizeof(dist)); dist[0] = 0; inq[0] = 1; cnt[0] = 1; while(!q.empty()) { int u = q.front(); q.pop(); inq[u] = 0; for(int i = 0; i<G[u].size(); i++) { int v = G[u][i].v, w= G[u][i].w; if(dist[v]>dist[u] + w) { dist[v] = dist[u] + w; if(!inq[v]) q.push(v),inq[v] = 1; if(++cnt[v]>n) return true; } } } return false; } bool test(int mid,int n) { for(int i = 1; i<=n; i++) for(int j = 0; j<G[i].size(); j++) G[i][j].w -=mid; int ret = spfa(n); for(int i = 1; i<=n; i++) for(int j = 0; j<G[i].size(); j++) G[i][j].w +=mid; return ret; } int main() { int V,E; while(~scanf("%d%d",&V,&E)) { init(V); int ub = 0; int u ,v ,w; for(int i = 0; i<E; i++) { scanf("%d%d%d",&u,&v,&w); G[u].push_back(node(v,w)); ub = max(w,ub); } for(int i = 1; i<=V; i++) G[0].push_back(node(i,0)); int L = 1, R = ub; if(test(L,V)) puts("No Solution"); else if(!test(ub+1,V)) puts("Infinite"); else { while(L<R) { int mid = L + (R -L)/2; if(test(mid,V)) R = mid ; else L = mid + 1; } printf("%d ",L-1); } } return 0; }