标签:hdu
题意:有n个点和m条有向边构成的网络,每条边有两个花费:
d:毁坏这条边的花费 b:重建一条双向边的花费
寻找这样两个点集,使得点集s到点集t满足 毁坏所有S到T的路径的费用和 > 毁坏所有T到S的路径的费用和 + 重建这些T到S的双向路径的费用和。
思路1:
然后这个无源汇带上下界网络流的可行流问题的求解方法见这里~~
建图就是上面说的那样啦~最后判断有没有可行流就是求一下我们所构造的这个新的网络的最大流~然后判断一下这个最大流是否满流~(即判断最大流是否和附加源点的流出总量相等~~)
code:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> #include<string> #include<queue> #include<map> #include<set> #include<cmath> #include<cstdlib> using namespace std; #define INF 0x3f3f3f3f #define PI acos(-1.0) #define mem(a, b) memset(a, b, sizeof(a)) typedef pair<int,int> pii; typedef long long LL; //------------------------------ const int maxn = 210; int n,m; struct Edge{ int to, cap, rev;//终点 容量 反向边 Edge(int to_ = 0, int cap_ = 0, int rev_ = 0){ to = to_; cap = cap_; rev = rev_; } }; vector<Edge> g[maxn]; int level[maxn];//顶点到源点的距离标号 int iter[maxn]; void add_Edge(int from, int to, int cap){ Edge tmp1(to, cap, g[to].size()); g[from].push_back(tmp1); Edge tmp2(from, 0, g[from].size()-1); g[to].push_back(tmp2); } void bfs(int s){ memset(level, -1, sizeof(level)); queue<int> q; level[s] = 0; q.push(s); while(!q.empty()){ int v = q.front(); q.pop(); for(int i = 0; i < g[v].size(); i++){ Edge& e = g[v][i]; if(e.cap > 0 && level[e.to] < 0){ level[e.to] = level[v] + 1; q.push(e.to); } } } } int dfs(int v, int t, int f){ if(v == t) return f; for(int& i = iter[v]; i < g[v].size(); i++){ Edge& e = g[v][i]; if(e.cap > 0 && level[v] < level[e.to]){ int d = dfs(e.to, t, min(e.cap, f)); if(d > 0){ e.cap -= d; g[e.to][e.rev].cap += d; return d; } } } return 0; } int max_flow(int s, int t){ int flow = 0; for(;;){ bfs(s); if(level[t] < 0) return flow; memset(iter, 0, sizeof(iter)); int f; while((f = dfs(s, t, INF)) > 0){ flow += f; } } } //------------------上面是最大流模板部分 正确---------------------- int sum; int mi[maxn];//这个是用来保存每个点的 入度-出度 的值,就是论文里的M(i); void init(){ for(int i = 0; i < maxn; i++){//网络流里的清空,不要忘记 g[i].clear(); } memset(mi, 0, sizeof(mi)); scanf("%d%d",&n,&m); int u, v, d, b; for(int i = 1; i <= m; i++){ scanf("%d%d%d%d",&u, &v, &d, &b); mi[u]-=d; mi[v]+=d; add_Edge(u, v, b);//加边加上的是每条边的下界值 } sum = 0;//sum保存的是源点的所有流出流量 for(int i = 1; i <= n; i++){ if(mi[i] < 0) add_Edge(i, n+1, -mi[i]); else if(mi[i] > 0) { add_Edge(0, i, mi[i]); sum += mi[i]; } } } void solve(){ int ans = max_flow(0, n+1); if(ans == sum) printf("happy\n"); else printf("unhappy\n"); } int main(){ int t; int cas = 0; scanf("%d",&t); while(t--){ init(); printf("Case #%d: ",++cas); solve(); } return 0; }
思路2:
阔以试想~如果对于所有单一的一个点组成的集合S来说,都不能满足
S到T的路径的费用和 > 毁坏所有T到S的路径的费用和 + 重建这些T到S的双向路径的费用和 的话,那么任意的点的集合构成的S集合也一定并不能满足上述条件~~~反之如果存在集合满足上述条件的话,就一定存在单一的点满足上述条件~~~~
这样我们其实只用枚举点然后判断就好啦。。。。。Orz。。。
code:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<vector> using namespace std; const int maxn = 205; int n, m; int D[maxn][maxn], B[maxn][maxn]; vector<int> in[maxn], out[maxn]; void init(){ for(int i = 0; i < maxn; i++){ in[i].clear(); out[i].clear(); } memset(D,0,sizeof(D)); memset(B,0,sizeof(B)); scanf("%d%d",&n,&m); int u, v, dd, bb; for(int i = 1; i <= m; i++){ scanf("%d%d%d%d",&u,&v,&dd,&bb); out[u].push_back(v); in[v].push_back(u); D[u][v] = dd; B[u][v] = bb; } } bool deal(int u){ int x = 0; for(int i = 0; i < in[u].size(); i++){ int v = in[u][i]; x += D[v][u]; } int y = 0; for(int i = 0; i < out[u].size(); i++){ int v = out[u][i]; y = y + D[u][v] + B[u][v]; } if(y < x) return true; return false; } void solve(){ for(int i = 1; i <= n; i++){ if(deal(i)){ printf("unhappy\n"); return; } } printf("happy\n"); } int main(){ int t; int cas = 0; scanf("%d",&t); while(t--){ init(); printf("Case #%d: ",++cas); solve(); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
hdu 4940 Destroy Transportation system( 无源汇上下界网络流的可行流判断 )
标签:hdu
原文地址:http://blog.csdn.net/u013382399/article/details/46816197