P2410 [SDOI2009]最优图像 乘法费用流
题目
P2410 [SDOI2009]最优图像(https://www.luogu.com.cn/problem/P2410)
题目背景
小 E 在好友小 W 的家中发现一幅神奇的图画,对此颇有兴趣。
题目描述
这幅画可以被看做一个包含 n×m 个像素的黑白图像,为了方便起见,我们用 0 表示白色像素,1 表示黑色像素。小 E 认为这幅图画暗藏玄机,因此他记录下了这幅图像中每行、每列的黑色像素数量,以回去慢慢研究其中的奥妙。
有一天,小 W 不慎将图画打湿,原本的图像已经很难分辨。他十分着急,于是找来小 E,希望共同还原这幅图画。根据打湿后的图画,他们无法确定真正的图像,然而可以推测出每个像素原本是黑色像素的概率
%。那么,一个完整的图像的出现概率就可以定义为:
其中 表示在还原后的图像中,像素是白色(0)还是黑色(1), 表示若 ,则该表达式的值为 1,否则为 0。
换句话说,一个完整图像出现概率就等于其所有黑色像素的出现概率之积。显然,图像的黑色像素不能包含概率为 0 的像素。
然而,小 E 对此也无能为力。因此他们找到了会编程的小 F,也就是你,请你根据以上信息,告诉他们最有可能是原始图像的答案是什么。
输入格式
第一行是两个整数 n, m,表示图像大小。
第 2 到第 (n + 1)行,每行 m 个整数,第 (i + 1)行的第 j 个整数
表示第 i 行第 j 列的像素是黑色的概率。
接下来一行有 n 个整数,第 i 个整数 表示第 i 行中黑色像素的个数。
接下来一行有 m 个整数,第 i 个整数 表示第 i 列中黑色像素的个数。
输出格式
本题存在 Special Judge。
输出 n 行每行一个长度为 m 的只含字符 0 和字符 1 的字符串,表示答案。
输入数据保证至少存在一个可能的图像。如果有多种最优图像,任意输出一种即可。
输入
2 2
90 10
20 80
1 1
1 1
输出
10
01
说明/提示
样例输入输出 1 解释
共有两种可能的图像:
01
10
10
01
前者的出现概率是 0.1×0.2=0.02,后者的出现概率是 0.9×0.8=0.72,故后者是最优图像。
数据规模与约定
对于 20% 的数据,保证 n,m≤5。
对于 100% 的数据,保证 1≤n,m≤100,,0≤a_i≤m,0≤b_i≤n。
思路:
标准的费用流,每行和每列作为点。但是这里的费用是概率,并且是相乘。那么spfa改成最长路。
+法改为x,-法改为/。并且反向边的费用为倒数,不是负数。
#include<bits/stdc++.h>
using namespace std;
//x->y incf w
const int inf=0x3f3f3f3f;
const double eps=1e-6;
int cnt=1,n,m,s,t;
double dis[405],w[200005];
int a[105],b[105],vis[405],val[105][105],mp[105][105];
int h[405],to[200005],ver[200005],incf[200005],cur[405];
inline int read() {
int x=0,f=1;char s=getchar();
while(s>'9'||s<'0') {if(s=='-') f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
return x*f;
}
inline void add(int x,int y,int z,double v) {
to[++cnt]=y;
ver[cnt]=h[x];
incf[cnt]=z;
w[cnt]=v;
h[x]=cnt;
}
inline void add_d(int x,int y,int z,double v) {add(x,y,z,v);add(y,x,0,1.0/v);}
inline bool spfa() {
memset(dis, 0, sizeof dis);
memset(vis, false, sizeof vis);
queue<int> Q;
dis[t]=1.00;Q.push(t);
while(Q.size()) {
int x=Q.front();Q.pop();
vis[x]=0;
for(int i=h[x];i;i=ver[i]) {
int y=to[i];
if((dis[y]<dis[x]*w[i^1])&&(incf[i^1])) {
dis[y]=dis[x]*w[i^1];
if(!vis[y]) {vis[y]=1;Q.push(y);}
}
}
}
return dis[s]>0;
}
int dfs(int x,int flow) {
if(x==t) return flow;
vis[x]=1;
int rest=flow;
for(int i=h[x];i&&rest;i=ver[i]) {
int y=to[i];
if(!vis[y]&&(fabs(dis[x]-dis[y]*w[i])<=eps)&&incf[i]) {
int k = dfs(y,min(rest,incf[i]));
rest-=k;incf[i]-=k;incf[i^1]+=k;
}
}
vis[x]=0;
return flow-rest;
}
int main() {
n=read(),m=read();
int maxflow=0;
s=n+m+1;t=n+m+2;
for(int i=1;i<=n;++i) {
for(int j=1;j<=m;++j) {
int x = read();
if (x) add_d(i,j+n,1,x*0.01);
}
}
for(int i=1;i<=n;++i) {
int x = read();
add_d(s,i,x,1.0);
}
for(int i=1;i<=m;++i) {
int x = read();
add_d(i+n,t,x,1.0);
}
while(spfa()) {
// memcpy(cur, h, sizeof h);
// dfs(s,inf);
while(dfs(s, INT_MAX)) memset(vis, false, sizeof vis);
}
for(int x=1;x<=n;++x) {
for(int i=h[x];i;i=ver[i]) {
int y=to[i];
if(y==s) continue;
if(!incf[i]) mp[x][y-n]=1;
}
}
for(int x=1;x<=n;++x) {
for(int y=1;y<=m;++y) {
printf("%d",mp[x][y]);
}
printf("\n");
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)