zoukankan      html  css  js  c++  java
  • 【COGS】894. 追查坏牛奶

    http://cojs.tk/cogs/problem/problem.php?pid=894

    题意:n个点m条边的加权网络,求最少边数的按编号字典序最小的最小割。(n<=32, m<=1000)

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    struct Gr {
    	static const int N=33, M=1005, oo=~0u>>1;
    	struct E { int next, from, to, cap; }e[M<<1];
    	int ihead[N], cnt, d[N], p[N], gap[N], cur[N];
    	Gr() { memset(ihead, 0, sizeof ihead); cnt=1; }
    	Gr & operator=(const Gr &g) {
    		memcpy(ihead, g.ihead, sizeof g.ihead);
    		memcpy(e, g.e, sizeof g.e);
    		cnt=g.cnt;
    		return *this;
    	}
    	void add(int u, int v, int cap) {
    		e[++cnt]=(E){ihead[u], u, v, cap}; ihead[u]=cnt;
    		e[++cnt]=(E){ihead[v], v, u, 0}; ihead[v]=cnt;
    	}
    	ll isap(int s, int t, int n) {
    		for(int i=0; i<=n; ++i) d[i]=0, gap[i]=0, cur[i]=ihead[i];
    		gap[0]=n; int u=s, i, f; ll ret=0;
    		while(d[s]<n) {
    			for(i=cur[u]; i; i=e[i].next) if(e[i].cap && d[e[i].to]+1==d[u]) break;
    			if(i) {
    				cur[u]=i; p[e[i].to]=i; u=e[i].to;
    				if(u==t) {
    					for(f=oo; u!=s; u=e[p[u]].from) f=min(f, e[p[u]].cap);
    					for(u=t; u!=s; u=e[p[u]].from) e[p[u]].cap-=f, e[p[u]^1].cap+=f;
    					ret+=f;
    				}
    			}
    			else {
    				if(!(--gap[d[u]])) break;
    				d[u]=n; cur[u]=ihead[u];
    				for(i=ihead[u]; i; i=e[i].next) if(e[i].cap && d[e[i].to]+1<d[u]) d[u]=d[e[i].to]+1;
    				++gap[d[u]];
    				if(u!=s) u=e[p[u]].from;
    			}
    		}
    		return ret;
    	}
    }g, G;
    int n, m, arr[Gr::M], tot;
    int main() {
    	freopen("milk6.in", "r", stdin);
    	freopen("milk6.out", "w", stdout);
    	scanf("%d%d", &n, &m);
    	for(int i=1; i<=m; ++i) {
    		int x, y, cap;
    		scanf("%d%d%d", &x, &y, &cap);
    		g.add(x, y, cap*(m+1)+1);
    	}
    	ll ans=0, f;
    	G=g;
    	f=G.isap(1, n, n);
    	for(int i=1; i<=m; ++i) {
    		int id=i<<1, cap=g.e[id].cap;
    		g.e[id].cap=g.e[id^1].cap=0;
    		G=g;
    		ll mn=G.isap(1, n, n);
    		if(mn+cap==f) arr[++tot]=i, ans+=(cap-1)/(m+1), f=mn;
    		else g.e[id].cap=cap, g.e[id^1].cap=0;
    	}
    	printf("%lld %d ", ans, tot);
    	for(int i=1; i<=tot; ++i) printf("%d ", arr[i]);
    	return 0;
    }
    

      

    神题...在uoj群被神犇们吊打&裱

    = =这么水的usaco training我都不会做= =

    首先求最少边的话可以直接将权值变为$w*(m+1)+1$,然后就是最小割。理由很简单,最小割是$sum_{i为一条割边} (w[i]*(m+1)+1) = (m+1)sum_{i为一条割边} w[i] + c$首先我们分离出了原来没有改变权值的割,显然这样做$sum_{i为一条割边} w[i]$是原图的最小割,因为乘上$(m+1)$后始终大于边数,和边数$c$都是常数= =。其次我们在求改变权值后的最小割后,比较完原图最小割后还比较了右边常数$c$,而$c$正是割边数。而$(m+1)$这个乘数也是因为割边数<=m最大可能到了m,可能会影响到原来图上的边权值,所以乘上$(m+1)$来消除影响。

    那么现在问题变为求普通的字典序最少的最小割。我们考虑从小到大枚举边然后删边。

    如果删掉$i$这条边时,最小割变小的值恰好为$i$改变后的权值,那么显然$i$是割边,此时维护的最小割减小,删掉$i$不恢复。

    否则把删掉的边恢复。

  • 相关阅读:
    [LeetCode 116 117]
    看几道JQuery试题后总结(下篇)
    插入排序及其扩展
    Operation not permitted引发的惊魂72小时
    dddd
    天底下什么人都有,不要跟他们一般见识就是了
    qt宽字符串中文乱码(codec->toUnicode值得学习)
    qt事件传递过程和处理
    qt新进程工作目录的设置(工作目录确实是被子进程继承的,但也可以设置)
    面试都爱问的委托和事件(纠正)
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4307241.html
Copyright © 2011-2022 走看看