• CF1430G Yet Another DAG Problem


    CF1430G

    最小割:

    对于 (w_i imes(a_u-a_v)), 拆成 (w_ia_u)(-w_ia_v), 这样就把权重拆到了点上。

    首先显然地, 每个点的权值都在 [0,n-1] 之间, 于是可以跑最小割。

    要保证网络图里的边权为整数, 给所有边加上同一个较大值即可。

    #include <bits/stdc++.h>
    typedef long long LL;
    using namespace std;
    
    const int N = 23, M = 1e5+23;
    const LL bignum = 4e11, inf = 1ll << 60;
    
    int n, w[N], m;
    int id[N][N], tot, S, T;
    
    int ecnt = 1, hd[M], cur[M], nt[M], vr[M];
    LL cap[M];
    void ad(int x, int y, LL w) {
    	nt[++ecnt] = hd[x], hd[x] = ecnt;
    	vr[ecnt] = y, cap[ecnt] = w;
    }
    void ad_e(int x, int y, LL w) {
    	ad(x, y, w), ad(y, x, 0);
    }
    
    int q[M], h, t, d[M];
    bool bfs() {
    	for (int i = 1; i <= tot; ++i) d[i] = -1;
    	d[q[h = t = 1] = S] = 0;
    	while (h <= t) {
    		int x = q[h ++];
    		for (int i = hd[x],y; i; i = nt[i])
    			if (cap[i] && -1 == d[y = vr[i]])
    				d[q[++t] = y] = d[x] + 1;
    	}
    	return -1 != d[T];
    }
    
    LL dfs(int x, LL flw) {
    	if (x == T) return flw;
    	LL rst = flw;
    	for (int &i=cur[x],y; i; i = nt[i])
    		if (cap[i] && d[y = vr[i]] == d[x] + 1) {
    			LL tmp = dfs(y, min(cap[i], rst));
    			if(!tmp) d[y] = -1;
    			else cap[i] -= tmp, cap[i^1] += tmp, rst -= tmp;
    			if(!rst) break;
    		}
    	return flw - rst;
    }
    
    bool vis[M];
    void dfs2 (int x) {
    	vis[x] = true;
    	for (int i = hd[x]; i; i = nt[i])
    		if(cap[i] && !vis[vr[i]])
    			dfs2(vr[i]);
    }
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= n; ++ i) for (int j = 0; j <= n; ++ j) id[i][j] = ++ tot;
    	S = ++tot, T = ++tot;
    	for (int i = 0; i < m; ++ i) {
    		int x, y, z; scanf("%d%d%d", &x, &y, &z);
    		w[x] += z, w[y] -= z;
    		for (int j = 0; j <= n-1; ++ j) ad_e(id[y][j], id[x][j+1], inf);
    	}
    	for (int i = 1; i <= n; ++ i) {
    		ad_e(S, id[i][0], inf), ad_e(id[i][n], T, inf);
    		for (int j = 0; j < n; ++ j) ad_e(id[i][j], id[i][j+1], (LL)w[i] * j + bignum);
    	}
    	while (bfs()) {
    		for (int i = 1; i <= tot; ++ i) cur[i] = hd[i];
    		int now = 0;
    		while ((now = dfs(S, inf)));
    	}
    	dfs2(S);
    	for (int i = 1; i <= n; ++ i) {
    		int ans = 0;
    		for (int j = 0; j < n; ++ j) if(vis[id[i][j]]) ans = j;
    		cout << ans << ' ';
    	}
    	return 0;
    }
    

    状压:

    可以将 DAG 分层, 相邻两层的点权差为 1, 发现显然是可以做到的, 最后从 dp 状态逆推点权即可。

    #include <bits/stdc++.h>
    typedef long long LL;
    
    using namespace std;
    
    const int N = 18;
    const LL inf = 1e18;
    
    int n, m, e[N][N], in[N], lg[1 << N];
    int Sin[1 << N];
    LL Soutval[1 << N];
    LL dp[1 << N];
    int pre[1 << N];
    
    #define lowb(x) (x&(-x))
    
    int ans[N];
    void giao(int x, int v) {
    	if(!x) return;
    	giao(pre[x], v + 1);
    	x = pre[x] ^ x;
    	while (x) {
    		ans[lg[lowb(x)]] = v;
    		x &= x-1;
    	}
    }
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	int all = (1 << n) - 1;
    	for (int i = 0; i < m; ++ i) {
    		int x, y, z; scanf("%d%d%d", &x, &y, &z);
    		--x, --y;
    		e[x][y] = z;
    		in[y] |= 1 << x;
    	}
    	for (int i = 0; i < N; ++ i) lg[1 << i] = i;
    	for (int S = 1; S < (1 << n); ++ S) {
    		int x = lowb(S), lgx = lg[x];
    		Sin[S] = Sin[S ^ x] | in[lgx];
    		LL up = 0ll, down = 0ll;
    		for (int j = 0; j < n; ++j)
    			if((S >> j) & 1)
    				down += e[j][lgx];
    			else
    				up += e[lgx][j];
    		Soutval[S] = Soutval[S ^ x] + up - down;
    		dp[S] = inf;
    	}
    	for (int S = 0; S < (1 << n); ++ S) {
    		int T = all ^ S;
    		for (int nS = T; nS; nS = T & (nS - 1))
    			if((S & Sin[nS]) == Sin[nS]) {
    				if(dp[S | nS] > dp[S] + Soutval[S]) {
    					dp[S | nS] = dp[S] + Soutval[S];
    					pre[S | nS] = S;
    				}
    			}
    	}
    	giao(all, 0);
    	for (int i = 0; i < n; ++i) cout << ans[i] << ' ';
    	return 0;
    }
    
  • 相关阅读:
    轻量级前端MVVM框架avalon
    Android开发:TextView添加超链接的简便方法
    那些年一起学过的面向对象之:4 面向对象的三大特征:封装、继承、多态
    iOS 如何创建单例对象
    phing用户手册第四章Getting Started译文
    C语言中scanf/fscanf 的%[]和%n说明符的使用方法
    listview改变选中行字体颜色
    oracle数据库单个数据文件的大小限制
    古堡算式
    java反射--注解的定义与运用以及权限拦截
  • 原文地址:https://www.cnblogs.com/tztqwq/p/14421703.html
Copyright © 2020-2023  润新知