zoukankan      html  css  js  c++  java
  • 【CF】CF1430_G Yet Another DAG Problem_最小割/网络流/状压dp

    链接

    codeforces 1430G

    题面

    题解

    状压dp

    这个方法官方题解里面写得还挺好的。

    我就不写全了。仅仅简单地记录一下而已。

    • 我们考虑最终这幅图相当于说你给他分个层,使得每条边都从深度浅的连向深度深的。
    • 首先我们能用一些方法把边权变成点权。这样事情就由深度差乘边权变成了深度乘点权。好处理多了。
    • 分层了之后,自然就有一个结论:层数不超过点数。
    • 分层了,那我们就用状压dp,记(dp_{i,j})表示当前分完了第i层,已经分好了的集合为j。
    • 现在我们可以枚举子集转移了,复杂度(O(n3^n))
    • 我们希望能枚举点转移。但是硬转移肯定是不行的,因为我们有可能连出在同一层的边。那我们同一层的点拓扑排序完了之后倒叙添加就不会有这种事情了。

    最小割

    • 我们同样边权变点权。记点权为(a_i)
    • 我们对于每个点分出一组n个点,编号从1到n,分别表示这个点选择这个深度,并由第i组点的第j个点向该组第j+1个点连一条((j+1)a_i)的边。这样我们就可以计算出代价了,接下来我们要加限制。
    • 限制,如果有一条边(x,y),那么对于每个深度的x的点向最浅的一直到下个深度的y的点连一条INF边。
    • 注意到可能会有负权边。考虑到每一组的计算代价的边会且只会割一条。那我们给这些边统一加一个超级大数就行了。具体来说,这个超级大数可以参考最小的负权边来定。
    • 最后最小割,用一个bfs走还能走的边给点染色。然后看看那些从被染色的点到没被染色的点的边就是被割掉边。

    代码

    状压dp

    #include<bits/stdc++.h>
    #define LL long long
    #define MAXN 18
    #define INF 1000000000000
    using namespace std;
    template<typename T> void Read(T &cn)
    {
    	char c; int sig = 1;
    	while(!isdigit(c = getchar())) if(c == '-') sig = 0;
    	if(sig) {cn = c-48; while(isdigit(c = getchar())) cn = cn*10+c-48; }
    	else    {cn = 48-c; while(isdigit(c = getchar())) cn = cn*10+48-c; }
    }
    template<typename T> void Write(T cn)
    {
    	int wei = 0; T cm = 0; int cx = cn%10; cn/=10;
    	if(cn < 0 || cx < 0) {putchar('-'); cn = 0-cn; cx = 0-cx; }
    	while(cn)cm = cm*10+cn%10,cn/=10,wei++;
    	while(wei--)putchar(cm%10+48),cm/=10;
    	putchar(cx+48);
    }
    template<typename T> void WriteL(T cn) {Write(cn); puts(""); }
    template<typename T> void WriteS(T cn) {Write(cn); putchar(' '); }
    template<typename T> void Max(T &cn, T cm) {cn = cn < cm ? cm : cn; }
    template<typename T> void Min(T &cn, T cm) {cn = cn < cm ? cn : cm; }
    int n,m;
    struct Dp_lai{
    	int a[MAXN+1];
    	LL ans;
    	void qing() {ans = INF; memset(a,0,sizeof(a)); }
    	void outit() {for(int i = 1;i<=n;i++) WriteS(a[i]); puts(""); }
    };
    int e[MAXN+1][MAXN+1], g[MAXN+1];
    LL de[MAXN+1];
    Dp_lai f[1<<MAXN];
    int du[MAXN+1], dui[MAXN+1];
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	Read(n); Read(m);
    	for(int i = 1;i<=n;i++) for(int j = 1;j<=n;j++) e[i][j] = 0;
    	memset(du,0,sizeof(du)); memset(de,0,sizeof(de));
    	for(int i = 1;i<=m;i++) {int bx,by; LL bz; Read(bx); Read(by); Read(bz); e[by][bx] = 1; de[bx] += bz; de[by] -= bz; du[bx]++; }
    	for(int i = 1;i<=n;i++)
    	{
    		g[i] = 0;
    		for(int j = 1;j<=n;j++) if(e[j][i]) g[i] |= 1<<(j-1);
    	}
    	int l = 0, r = 0;
    	for(int i = 1;i<=n;i++) if(!du[i]) dui[++r] = i;
    	while(l < r)
    	{
    		int dang = dui[++l];
    		for(int i = 1;i<=n;i++) if(e[dang][i]) 
    		{
    			du[i]--;
    			if(!du[i]) dui[++r] = i;
    		}
    	}
    	for(int i = 0;i<(1<<n);i++) f[i].qing(); 
    	f[0].ans = 0; 
    	for(int i = 1;i<=n;i++) for(int j = n;j>=1;j--) for(int k = 0;k<(1<<n);k++)
    	{
    		int bx = dui[j];
    		if(((k&(1<<(bx-1)))!=0) || ((k&g[bx])!=g[bx]) || (f[k].ans+i*de[bx] >= f[k|(1<<(bx-1))].ans)) continue;
    		f[k|(1<<(bx-1))] = f[k]; f[k|(1<<(bx-1))].ans += i*de[bx]; f[k|(1<<(bx-1))].a[bx] = i;
    	}
    	f[(1<<n)-1].outit();
    	return 0;
    }
    

    最小割

    #include<bits/stdc++.h>
    #define LL long long
    #define MAXN 20
    #define INF 1000000000
    using namespace std;
    template<typename T> void Read(T &cn)
    {
    	char c; int sig = 1;
    	while(!isdigit(c = getchar())) if(c == '-') sig = 0;
    	if(sig) {cn = c-48; while(isdigit(c = getchar())) cn = cn*10+c-48; }
    	else    {cn = 48-c; while(isdigit(c = getchar())) cn = cn*10+48-c; }
    }
    template<typename T> void Write(T cn)
    {
    	int wei = 0; T cm = 0; int cx = cn%10; cn/=10;
    	if(cn < 0 || cx < 0) {putchar('-'); cn = 0-cn; cx = 0-cx; }
    	while(cn)cm = cm*10+cn%10,cn/=10,wei++;
    	while(wei--)putchar(cm%10+48),cm/=10;
    	putchar(cx+48);
    }
    template<typename T> void WriteL(T cn) {Write(cn); puts(""); }
    template<typename T> void WriteS(T cn) {Write(cn); putchar(' '); }
    template<typename T> void Max(T &cn, T cm) {cn = cn < cm ? cm : cn; }
    template<typename T> void Min(T &cn, T cm) {cn = cn < cm ? cn : cm; }
    namespace Flow{
    	const int MAXB = MAXN*MAXN*MAXN*MAXN;
    	const int MAXD = MAXN*MAXN+2;
    	struct qwe{
    		int a,b,ne,f;
    		void mk(int ca, int cb, int cn, int cf) {a = ca; b = cb; ne = cn; f = cf; }
    	};
    	qwe a[MAXB*2+1];
    	int alen;
    	int head[MAXD+1], lst[MAXD+1];
    	int shen[MAXD+1], dui[MAXD+1];
    	int typ[MAXD+1];
    	int bfs(int cn, int cm, int ctot)
    	{
    		for(int i = 1;i<=ctot;i++) shen[i] = ctot+2, lst[i] = head[i];
    		int l = 0, r = 0; dui[++r] = cn; shen[cn] = 0;
    		while(l < r)
    		{
    			int dang = dui[++l];
    			for(int i = head[dang];i;i = a[i].ne)
    			{
    				int y = a[i].b;
    				int lin = shen[dang]+1;
    				if(!a[i].f || shen[y] <= lin) continue;
    				shen[y] = lin; dui[++r] = y;
    			}
    		}
    		return shen[cm] != ctot+2;
    	}
    	LL ansl;
    	int dfs(int cn, int cm, int liu)
    	{
    		if(cn == cm) {ansl = ansl + liu; return liu; }
    		for(int &i = lst[cn];i;i = a[i].ne)
    		{
    			int y = a[i].b;
    			if(!a[i].f || shen[y] != shen[cn]+1) continue;
    			int lin = dfs(y, cm, min(liu, a[i].f));
    			if(lin) {
    				a[i].f -= lin;
    				a[((i+1)^1)-1].f += lin;
    				return lin;
    			}
    		}
    		return 0;
    	}
    	void get_typ(int cn, int ctot)
    	{
    		for(int i = 1;i<=ctot;i++) shen[i] = 0, typ[i] = 0;
    		int l = 0, r = 0; shen[cn] = 1; typ[cn] = 1; dui[++r] = cn;
    		while(l < r)
    		{
    			int dang = dui[++l];
    			for(int i = head[dang];i;i = a[i].ne)
    			{
    				int y = a[i].b;
    				if(!a[i].f) continue;
    				typ[y] = 1; if(!shen[y]) shen[y] = 1, dui[++r] = y;
    			}
    		}
    	}
    	void flow(int cn, int cm, int ctot)
    	{
    		while(bfs(cn,cm,ctot)) while(dfs(cn,cm,INF)); 
    		get_typ(cn, ctot); 
    	}
    	void build() {alen = 0; memset(head,0,sizeof(head)); }
    	void lian(int cn, int cm, int cf) {a[++alen].mk(cn,cm,head[cn],cf); head[cn] = alen; }
    	void lian_d(int cn, int cm, int cf) {lian(cn,cm,cf), lian(cm,cn,0); }
    };
    using Flow::build;
    using Flow::lian_d;
    using Flow::flow;
    int n, m;
    int e[MAXN+1][MAXN+1];
    int de[MAXN+1];
    int ans[MAXN+1];
    int pos[MAXN+1][MAXN+1];
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	Read(n); Read(m);
    	for(int i = 1;i<=n;i++) for(int j = 1;j<=n;j++) e[i][j] = 0;
    	memset(de,0,sizeof(de));
    	for(int i = 1;i<=m;i++) {int bx,by; LL bz; Read(bx); Read(by); Read(bz); e[by][bx] = 1; de[bx]+=bz; de[by]-=bz; }
    	LL xiao = 0;
    	for(int i = 1;i<=n;i++) Min(xiao, (LL)de[i]); xiao = xiao*n-1;
    //	printf("xiao = %lld
    ",xiao);
    	build();
    	for(int i = 1;i<=n;i++) 
    	{
    		int lst = 1;
    		for(int j = 1;j<=n;j++) 
    		{
    			int xian = 1+n*(i-1)+j;
    			lian_d(lst, xian, de[i]*j-xiao);
    			pos[i][j] = Flow::alen;
    //			printf("  %d
    ",Flow::a[pos[i][j]].f);
    			for(int k = 1;k<=n;k++) if(e[i][k]) lian_d(lst, 1+n*(k-1)+j, INF);
    			lst = xian;
    		}
    		lian_d(lst, 1+n*n+1, INF);
    	}
    //	printf("pred
    ");
    	flow(1, 1+n*n+1, 1+n*n+1);
    //	printf("flow over
    ");
    	for(int i = 1;i<=n;i++) 
    	{
    		int lst = 1;
    		for(int j = 1;j<=n;j++)
    		{
    			int xian = 1+n*(i-1)+j;
    			if(Flow::typ[lst] == 1 && Flow::typ[xian] == 0) ans[i] = j;
    			lst = xian;
    		}
    	}
    	for(int i = 1;i<=n;i++) WriteS(ans[i]); puts("");
    	return 0;
    }
    
  • 相关阅读:
    教你一步一步做无线点餐项目(登录篇)
    用Android中的ActionBar来实现分页Title栏滑块效果
    IIS处理brower的一个页面请求(www.test.com/SX?a=1)的处理流程
    [转载]物化视图——数据仓库手册
    [WEB系统中的设计模式(暂时放在这里,看不大懂)]mvc在web系统中的模式与应用
    ORACLE的分布式管理
    C#中 中 A==B && C==D ? E: F语法的一点问题
    delete 和 truncate
    prototype.js开发者手册
    【一个不错的oracle数据库诊断例子,值得学习一下】Oracle数据库诊断案例redo log日志组处于高激活状态
  • 原文地址:https://www.cnblogs.com/czyarl/p/13832655.html
Copyright © 2011-2022 走看看