4950: [Wf2017]Mission Improbable
Time Limit: 1 Sec Memory Limit: 1024 MBSubmit: 146 Solved: 70
[ Submit][ Status][ Discuss]
Description
Input
Output
Sample Input
5 5
1 4 0 5 2
2 1 2 0 1
0 2 3 4 4
0 3 0 3 1
1 2 2 1 1
样例2
2 3
50 20 3
20 10 3
Sample Output
9
样例2
30
HINT
Source
一开始考虑,每个不为0的位置都拿到1,然后每行每列最大值不能动。然后又考虑到,如果行列最大值相同,
我们可以在他们交叉的位置放一个最大值即可,而不需要两个。因此转化成一个二分图匹配的问题。(显然不同的
最大值不会互相干扰,因为之间根本不可能有边)每成功匹配到一个,就可以多拿一个最大值。
#include<stdio.h>
#include<bitset>
#include<cstring>
using namespace std;
bitset<205> vis;
long long sum;
int n, m, num, match[510], h[205], mp[205][205], mi[205], mj[205];
struct edge{ int nxt, v;}e[100005];
inline void add(int u, int v){
e[++num].v = v, e[num].nxt = h[u], h[u] = num;
}
bool find(int u){
for(int i = h[u]; i; i = e[i].nxt){
int v = e[i].v;
if(!vis[v]){
vis[v] = true;
if(!match[v] || find(match[v]))
return match[v] = u;
}
}
return false;
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j){
scanf("%d", &mp[i][j]);
mi[i] = max(mi[i], mp[i][j]);
mj[j] = max(mj[j], mp[i][j]);
if(mp[i][j]) sum += mp[i][j] - 1;
}
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
if(mi[i] == mj[j] && mp[i][j])
add(i, j + n);
for(int i = 1; i <= n; ++i) if(mi[i]) sum -= mi[i] - 1;
for(int j = 1; j <= m; ++j) if(mj[j]) sum -= mj[j] - 1;
for(int i = 1; i <= n; ++i){
if(find(i)) sum += mi[i] - 1;
vis = 0;
}
printf("%lld\n", sum);
}
669



被折叠的 条评论
为什么被折叠?



