zoukankan      html  css  js  c++  java
  • P2410 [SDOI2009]最优图像 ZKW最大费用最大流

    $ color{#0066ff}{ 题目描述 }$

    小E在好友小W的家中发现一幅神奇的图画,对此颇有兴趣。它可以被看做一个包含N×M个像素的黑白图像,为了方便起见,我们用0表示白色像素,1表示黑色像素。小E认为这幅图画暗藏玄机,因此他记录下了这幅图像中每行、每列的黑色像素数量,以回去慢慢研究其中的奥妙。

    有一天,小W不慎将图画打湿,原本的图像已经很难分辨。他十分着急,于是找来小E,希望共同还原这幅图画。根据打湿后的图画,他们无法确定真正的图像,然而可以推测出每个像素原本是黑色像素的概率Pij%。那么,一个完整的图像的出现概率就可以定义为:

    img

    其中Sij表示在还原后的图像中,像素是白色(0)还是黑色(1)。换句话说,一个完整图像出现概率就等于其所有黑色像素的出现概率之积。显然,图像的黑色像素不能包含概率为0的像素。

    然而,小E对此也无能为力。因此他们找到了会编程的小F,也就是你,请你根据以上信息,告诉他们最有可能是原始图像的答案是什么。

    (color{#0066ff}{输入格式})

    输入文件image.in的第一行是两个正整数N和M,表示图像大小。

    接下来N行每行包含M个整数,表示每个像素是黑色像素的概率为Pij%。0 ≤ Pij < 100。

    接下来一行有N个非负整数,表示每一行中黑色像素的个数。

    接下来一行有M个非负整数,表示每一列中黑色像素的个数。

    (color{#0066ff}{输出格式})

    输出文件image.out包含一个N×M的01矩阵,表示你还原出的图像。输出不包含空格。图像每行、每列中1的个数必须与输入一致,且是所有可能的图像中出现概率最大的一个。输入数据保证至少存在一个可能的图像。如果有多种最优图像,任意输出一种即可。

    (color{#0066ff}{输入样例})

    2 2
    90 10
    20 80
    1 1
    1 1
    

    (color{#0066ff}{输出样例})

    10
    01
    

    (color{#0066ff}{数据范围与提示})

    样例解释:共有两种可能的图像:

    01 10 和 10 01 前者的出现概率是0.1×0.2=0.02,后者的出现概率是0.9×0.8=0.72,故后者是最优图像。

    对于20%的数据,N , M ≤ 5;

    对于100%的数据,N , M ≤ 100。

    (color{#0066ff}{题解})

    一看数据范围,显然的费用流啦

    但是注意这里是一个(prod)

    于是我们把边权变为概率

    反向边稍微改变一下,就是它分之一,这样就满足了

    然而。。。这题居然卡EK

    于是得写ZKW费用流才能过qwq

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    const int inf = 0x7fffffff;
    const int maxn = 5050;
    struct node {
    	int to, can;
    	double dis;
    	node *nxt, *rev;
    	node(int to = 0, int can = 0, double dis = 0, node *nxt = NULL): to(to), can(can), dis(dis), nxt(nxt) {
    		rev = NULL;
    	}
    };
    std::deque<int> q;
    node *head[maxn], *cur[maxn];
    double dis[maxn];
    const double eps = 1e-6;
    bool choose[120][120];
    bool vis[maxn];
    int n, m, s, t;
    LL ans;
    void add(int from, int to, double dis, int can) {
    	head[from] = new node(to, can, dis, head[from]);
    }
    void link(int from, int to, double dis, int can) {
    	add(from, to, dis, can);
    	add(to, from, 1.0 / dis, 0);
    	head[from]->rev = head[to];
    	head[to]->rev = head[from];
    }
    bool spfa() {
    	for(int i = s; i <= t; i++) dis[i] = -1, vis[i] = false, cur[i] = head[i];
    	q.push_front(s);
    	dis[s] = 1.0;
    	while(!q.empty()) {
    		int tp = q.front(); q.pop_front();
    		vis[tp] = false;
    		for(node *i = head[tp]; i; i = i->nxt)
    			if(dis[i->to] < dis[tp] * i->dis && i->can) {
    				dis[i->to] = dis[tp] * i->dis;
    				if(!vis[i->to]) {
    					if(!q.empty() && dis[i->to] < dis[q.front()]) q.push_back(i->to);
    					else q.push_front(i->to);
    					vis[i->to] = true;
    				}
    			}
    	}
    	return dis[t] > 0;
    }
    int dfs(int x, int change) {
    	if(x == t || !change) return change;
    	int flow = 0, ls;
    	vis[x] = true;
    	for(node *i = cur[x]; i; i = i->nxt) {
    		cur[x] = i;
    		if(!vis[i->to] && fabs(dis[i->to] - (dis[x] * i->dis)) <= eps && (ls = dfs(i->to, std::min(i->can, change)))) {
    			flow += ls;
    			change -= ls;
    			i->can -= ls;
    			i->rev->can += ls;
    			if(!change) break;
    		}
    	}
    	vis[x] = false;
    	return flow;
    } 
    void zkw() {
    	while(spfa()) dfs(s, inf);
    	for(int i = 1; i <= n; i++)
    		for(node *o = head[i]; o; o = o->nxt) {
    			if(o->to == s) continue;
    			if(!o->can) choose[i][o->to - n] = true;
    		}
    	for(int i = 1; i <= n; i++) {
    		for(int j = 1; j <= m; j++) printf("%d", choose[i][j]);
    		puts("");
    	}
    }
    			
    int main() {
    	n = in(), m = in(), s = 0, t = n + m + 1;
    	for(int i = 1; i <= n; i++)
    		for(int j = 1; j <= m; j++) {
    			int x = in();
    			if(x) link(i, n + j, x * 0.01, 1);
    		}
    	for(int i = 1; i <= n; i++) link(s, i, 1.0, in());
    	for(int i = 1; i <= m; i++) link(n + i, t, 1.0, in());
    	zkw();
    	return 0;
    }
    
  • 相关阅读:
    关于Dockerfile
    hiho一下 第六十四周 Right-click Context Menu
    hdu2642二维树状数组单点更新+区间查询
    东大oj-1511: Caoshen like math
    东大OJ-1588: Routing Table
    东大oj-1591 Circle of friends
    2015年辽宁省赛Interesting Tree
    东大OJ-1544: GG的战争法则
    迷宫问题-广度优先搜索
    vijos P1009清帝之惑之康熙
  • 原文地址:https://www.cnblogs.com/olinr/p/10458135.html
Copyright © 2011-2022 走看看