最開始寫費用流的時候,有且只會SPFA版的費用流,而且一直都夠用,一般來說只要建出了圖就贏了,網絡流怎么都不會超時。
。。。。這個情況到今天被終結了。。。
終結者見下:
--------------------------------------------------------------------------------------------------------
最優圖像
【題目描述】
小E在好友小W的家中發現一幅神奇的圖畫,對此頗有興趣。它可以被看做一個包含N×M個像素的黑白圖像,為了方便起見,我們用0表示白色像素,1表示黑色像素。小E認為這幅圖畫暗藏玄機,因此他記錄下了這幅圖像中每行、每列的黑色像素數量,以回去慢慢研究其中的奧妙。
有一天,小W不慎將圖畫打濕,原本的圖像已經很難分辨。他十分著急,于是找來小E,希望共同還原這幅圖畫。根據打濕后的圖畫,他們無法確定真正的圖像,然而可以推測出每個像素原本是黑色像素的概率Pij%。那么,一個完整的圖像的出現概率就可以定義為
,其中Sij表示在還原后的圖像中,像素是白色(0)還是黑色(1)。換句話說,一個完整圖像出現概率就等于其所有黑色像素的出現概率之積。顯然,圖像的黑色像素不能包含概率為0的像素。
然而,小E對此也無能為力。因此他們找到了會編程的小F,也就是你,請你根據以上信息,告訴他們最有可能是原始圖像的答案是什么。
【輸入文件】
輸入文件image.in的第一行是兩個正整數N和M,表示圖像大小。
接下來N行每行包含M個整數,表示每個像素是黑色像素的概率為Pij%。0 ≤ Pij < 100。
接下來一行有N個非負整數,表示每一行中黑色像素的個數。
接下來一行有M個非負整數,表示每一列中黑色像素的個數。
【輸出文件】
輸出文件image.out包含一個N×M的01矩陣,表示你還原出的圖像。輸出不包含空格。圖像每行、每列中1的個數必須與輸入一致,且是所有可能的圖像中出現概率最大的一個。輸入數據保證至少存在一個可能的圖像。如果有多種最優圖像,任意輸出一種即可。
【樣例輸入】
2 2
90 10
20 80
1 1
1 1
【樣例輸出】
10
01
【樣例解釋】
共有兩種可能的圖像:
01
10
和
10
01
前者的出現概率是0.1×0.2=0.02,后者的出現概率是0.9×0.8=0.72,故后者是最優圖像。
【數據規模和約定】
對于20%的數據,N , M ≤ 5;
對于100%的數據,N , M ≤ 100。
--------------------------------------------------------------------------------------------------------
這道題的時限是兩秒。
這道題的做法是把行和列拿出來,如果i行j列出現1的就把i行與j列連一條流量為1,費用為log(p[i][j])的邊。源與每行、每列與匯都連一條流量為行、列1的個數,費用為0的邊,然后求最大費用最大流。流過的邊所連的行和列的交點就有一個點。
當時看到n<=100,總點數就是2n,心想很小。。。但沒想到邊有10000條,用SPFA寫出來了過后開始只有60分。。后來優化到了70分,就是SPFA極限了,剩下的點根本進不了2秒。
SPFA的時間復雜度是O(km)的,m是邊數,k是常數,在這題特殊的圖里面一次只能增廣1的流量。。所以總的時間復雜度達到了O(100*100*O(SPFA)) > 100000000。。。
于是沒辦法,把zkw的網絡流學了。。
其實zkw網絡流增廣的時候是sap,修改標號的時候是KM。。。。所以學起來很順暢,寫起來也比SPFA的短,但是效率要高很多:
膜拜啊!
代碼:
1
/**//*
2
* $File: costflow.cpp
3
*/
4
5
#include <iostream>
6
#define MAXNODE 500
7
#define MAXEDGE MAXNODE*MAXNODE
8
#define MIN(a,b) ((a)<(b)?(a):(b))
9
#define OPPOSITE(x) (((x)&1)?((x)+1):((x)-1))
10 #define INFINIT ~0U>>1
11
12
using namespace std;
13
14
15
int n,m;
16
int N,S,T;
17
int begin[MAXNODE+1],end[MAXEDGE+1],next[MAXEDGE+1],c[MAXEDGE+1],cost[MAXEDGE+1],d[MAXNODE+1],cur[MAXNODE+1];
18
bool hash[MAXNODE+1];
19
int Count = 0;
20
int aug(int u,int f)
{
21
if (u == T) return f;
22
hash[u] = true;
23
for (int now = cur[u]; now; now = next[now])
24
if (c[now]&&!hash[end[now]]&&d[u] == d[end[now]]+cost[now])
25
if (int tmp = aug(end[now],MIN(f,c[now])))
26
return c[now] -= tmp,c[OPPOSITE(now)] += tmp,cur[u] = now,tmp;
27
return 0;
28
}
29
bool modlabel()
{
30
int tmp = INFINIT;
31
for (int i = 1; i<=N; i++)
32
if (hash[i])
33
for (int now = begin[i]; now; now = next[now])
34
if (c[now]&&!hash[end[now]])
35
tmp = MIN(tmp,d[end[now]]+cost[now]-d[i]);
36
if (tmp == INFINIT)
37
return true;
38
for (int i = 1; i<=N; i++)
39
if (hash[i])
40
hash[i] = false,d[i] += tmp;
41
return false;
42
}
43
int CostFlow()
{
44
int costflow = 0,tmp;
45
while (true)
{
46
for (int i = 1; i<=N; i++)
47
cur[i] = begin[i];
48
while (tmp = aug(S,~0U>>1))
{
49
costflow += tmp*d[S];
50
memset(hash,0,sizeof(hash));
51
}
52
if (modlabel())
53
break;
54
}
55
return costflow;
56
}
57
void AddEdge(int a,int b,int flow, int v)
{
58
Count++; next[Count] = begin[a]; begin[a] = Count; end[Count] = b; c[Count] = flow; cost[Count] = v;
59
Count++; next[Count] = begin[b]; begin[b] = Count; end[Count] = a; c[Count] = 0; cost[Count] = -v;
60
}
61
int main()
{
62
freopen("costflow.in","r",stdin);
63
freopen("costflow.out","w",stdout);
64
scanf("%d%d",&n,&m);
65
while (m--)
{
66
int t1,t2,t3,t4;
67
scanf("%d%d%d%d",&t1,&t2,&t3,&t4);
68
AddEdge(t1,t2,t3,t4);
69
}
70
S = 1,T = N = n;
71
printf("%d\n",CostFlow());
72
return 0;
73
}
74
75
今天先休息一下,整理一下思路有時間再詳細寫下過程~