【BZOJ4883】[Lydsy2017年5月月赛]棋盘上的守卫 KM算法

【BZOJ4883】[Lydsy2017年5月月赛]棋盘上的守卫

Description

在一个n*m的棋盘上要放置若干个守卫。对于n行来说,每行必须恰好放置一个横向守卫;同理对于m列来说,每列

必须恰好放置一个纵向守卫。每个位置放置守卫的代价是不一样的,且每个位置最多只能放置一个守卫,一个守卫

不能同时兼顾行列的防御。请计算控制整个棋盘的最小代价。

Input

第一行包含两个正整数n,m(2<=n,m<=100000,n*m<=100000),分别表示棋盘的行数与列数。

接下来n行,每行m个正整数

其中第i行第j列的数w[i][j](1<=w[i][j]<=10^9)表示在第i行第j列放置守卫的代价。

Output

输出一行一个整数,即占领棋盘的最小代价。

Sample Input

3 4
1 3 10 8
2 1 9 2
6 7 4 6

Sample Output

19
HINT
在(1,1),(2,2),(3,1)放置横向守卫,在(2,1),(1,2),(3,3),(2,4)放置纵向守卫。

题解:从来没想过KM的时间复杂度能完虐费用流~

将 行、列 和 格点 分成两个集合,集合间连边,边权就是该格点的费用,然后将边权变成相反数,用KM跑最大匹配,最后再将答案取相反数就行了

考场上写(chao)的zkw费用流被虐暴了

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
int n,m,now,cnt;
ll ans,temp;
int va[200010],vb[200010],to[200010],next[200010],head[200010],from[200010];
ll la[200010],lb[200010],val[200010];
int rd()
{
	int ret=0;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	gc=getchar();
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret;
}
void add(int a,int b,int c)
{
	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
int dfs(int x)
{
	va[x]=now;
	for(int i=head[x];i!=-1;i=next[i])
	{
		if(vb[to[i]]!=now)
		{
			if(!(la[x]+lb[to[i]]-val[i]))
			{
				vb[to[i]]=now;
				if(!from[to[i]]||dfs(from[to[i]]))
				{
					from[to[i]]=x;
					return 1;
				}
			}
			else	temp=min(temp,la[x]+lb[to[i]]-val[i]);
		}
	}
	return 0;
}
int main()
{
	n=rd(),m=rd();
	int i,j,a;
	ll b;
	memset(head,-1,sizeof(head));
	memset(la,0x80,sizeof(la));
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)
			a=(i-1)*m+j,b=-rd(),add(i,a,b),la[i]=max(la[i],b),add(j+n,a,b),la[j+n]=max(la[j+n],b);
	for(i=1;i<=n+m;i++)
	{
		while(1)
		{
			now++;
			temp=1ll<<60;
			if(dfs(i))	break;
			for(j=1;j<=n+m;j++)	if(va[j]==now)	la[j]-=temp;
			for(j=1;j<=n*m;j++)	if(vb[j]==now)	lb[j]+=temp;
		}
	}
	for(i=1;i<=n+m;i++)	ans+=la[i];
	for(i=1;i<=n*m;i++)	ans+=lb[i];
	printf("%lld",-ans);
	return 0;
}
时间: 2024-09-30 16:34:44

【BZOJ4883】[Lydsy2017年5月月赛]棋盘上的守卫 KM算法的相关文章

[bzoj4883][Lydsy2017年5月月赛]棋盘上的守卫

来自FallDream的博客,未经允许,请勿转载, 谢谢. 在一个n*m的棋盘上要放置若干个守卫.对于n行来说,每行必须恰好放置一个横向守卫:同理对于m列来说,每列 必须恰好放置一个纵向守卫.每个位置放置守卫的代价是不一样的,且每个位置最多只能放置一个守卫,一个守卫 不能同时兼顾行列的防御.请计算控制整个棋盘的最小代价. n*m<=10^5 费用流比较好想,把行和列拿出来,第i行向第j列连费用是a[i][j]的边,然后限制每行每列流量1即可. 但是费用流不是很科学(好像有人大力艹过了?),考虑优

BZOJ 4883 [Lydsy2017年5月月赛]棋盘上的守卫(最小生成环套树森林)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4883 [题目大意] 在一个n*m的棋盘上要放置若干个守卫. 对于n行来说,每行必须恰好放置一个横向守卫:同理对于m列来说, 每列必须恰好放置一个纵向守卫.每个位置放置守卫的代价是不一样的, 且每个位置最多只能放置一个守卫,一个守卫不能同时兼顾行列的防御. 请计算控制整个棋盘的最小代价. [题解] 我们将每行和每列看成一个点,用每个格子上的点的权值作为边, 这就构成了一个n+m个点的图

[Lydsy2017年4月月赛]抵制克苏恩

[Lydsy2017年4月月赛]抵制克苏恩 时间限制: 1 Sec  内存限制: 128 MB提交: 49  解决: 34[提交][状态][讨论版] 题目描述 小Q同学现在沉迷炉石传说不能自拔.他发现一张名为克苏恩的牌很不公平.如果你不玩炉石传说,不必担心,小Q同学会告诉你所有相关的细节.炉石传说是这样的一个游戏,每个玩家拥有一个 30 点血量的英雄,并且可以用牌召唤至多 7 个随从帮助玩家攻击对手,其中每个随从也拥有自己的血量和攻击力.小Q同学有很多次游戏失败都是因为对手使用了克苏恩这张牌,所

【BZOJ 4832 】 4832: [Lydsy2017年4月月赛]抵制克苏恩 (期望DP)

4832: [Lydsy2017年4月月赛]抵制克苏恩 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 275  Solved: 87 Description 小Q同学现在沉迷炉石传说不能自拔.他发现一张名为克苏恩的牌很不公平.如果你不玩炉石传说,不必担心,小Q 同学会告诉你所有相关的细节.炉石传说是这样的一个游戏,每个玩家拥有一个 30 点血量的英雄,并且可以用牌 召唤至多 7 个随从帮助玩家攻击对手,其中每个随从也拥有自己的血量和攻击力.小Q同学

bzoj 4836: [Lydsy2017年4月月赛]二元运算 -- 分治+FFT

4836: [Lydsy2017年4月月赛]二元运算 Time Limit: 8 Sec  Memory Limit: 128 MB Description 定义二元运算 opt 满足 现在给定一个长为 n 的数列 a 和一个长为 m 的数列 b ,接下来有 q 次询问.每次询问给定一个数字 c 你需要求出有多少对 (i, j) 使得 a_i  opt b_j=c . Input 第一行是一个整数 T (1≤T≤10) ,表示测试数据的组数. 对于每组测试数据: 第一行是三个整数 n,m,q (

4832: [Lydsy2017年4月月赛]抵制克苏恩]【解题报告】

戳我 4832: [Lydsy2017年4月月赛]抵制克苏恩 时间限制: 1 Sec  内存限制: 128 MB提交: 752  解决: 289[提交][][] 题目描述 小Q同学现在沉迷炉石传说不能自拔.他发现一张名为克苏恩的牌很不公平.如果你不玩炉石传说,不必担心,小Q 同学会告诉你所有相关的细节.炉石传说是这样的一个游戏,每个玩家拥有一个 30 点血量的英雄,并且可以用牌 召唤至多 7 个随从帮助玩家攻击对手,其中每个随从也拥有自己的血量和攻击力.小Q同学有很多次游戏失败都是 因为对手使用

bzoj4886 [Lydsy2017年5月月赛]叠塔游戏

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4886 [题解] 跟bzoj4883:http://www.cnblogs.com/galaxies/p/bzoj4833.html很相似啊 我们对于a,b离散后建点,那么一个卡片就相当于a到b有一条边. 现在要给边定向,使得每个点入度均为1. 贡献=每个点出度*该点权值 bzoj4883的时候谈过,这样的连通块要么是环套树要么是树. 肯定都有的一部分贡献是(deg[i]-1)*a[i](总

抵制克苏恩[Lydsy2017年4月月赛]

题目描述 小Q同学现在沉迷炉石传说不能自拔.他发现一张名为克苏恩的牌很不公平.如果你不玩炉石传说,不必担心,小Q同学会告诉你所有相关的细节.炉石传说是这样的一个游戏,每个玩家拥有一个 30 点血量的英雄,并且可以用牌召唤至多 7 个随从帮助玩家攻击对手,其中每个随从也拥有自己的血量和攻击力.小Q同学有很多次游戏失败都是因为对手使用了克苏恩这张牌,所以他想找到一些方法来抵御克苏恩.他去求助职业炉石传说玩家椎名真白,真白告诉他使用奴隶主这张牌就可以啦.如果你不明白我上面在说什么,不必担心,小Q同学会

【BZOJ 4832】 [Lydsy2017年4月月赛] 抵制克苏恩 期望概率dp

打记录的题打多了,忘了用开维记录信息了......我们用f[i][j][l][k]表示已经完成了i次攻击,随从3血剩j个,2血剩l个,1血剩k个,这样我们求出每个状态的概率,从而求出他们对答案的贡献并加和,一开始我用的期望忘了转移的时候不能用1而要用概率...... #include <cstdio> #include <cstring> #define r register using namespace std; typedef long double LD; inline i