BZOJ 2150+BZOJ 1854【二分图匹配】 两更+蜜汁数组(游戏+部落战争)

编程入门 行业动态 更新时间:2024-10-10 05:24:10

BZOJ 2150+BZOJ 1854【二分图匹配】 两更+<a href=https://www.elefans.com/category/jswz/34/1217618.html style=蜜汁数组(游戏+部落战争)"/>

BZOJ 2150+BZOJ 1854【二分图匹配】 两更+蜜汁数组(游戏+部落战争)

ps.看帖回帖是种美德      

  今天GET了一个新技能——二分图的匹配问题。

       怎么解释呢?就是有A,B两个集合,要求里面元素尽量1对1匹配。

下面的专业解释摘自 (谁叫我懒呢2333)

Renfei's Blog——

二分图的最大匹配、完美匹配

这篇文章讲无权二分图(unweighted bipartite graph)的最大匹配(maximum matching)和完美匹配(perfect matching),以及用于求解匹配的匈牙利算法(Hungarian Algorithm);不讲带权二分图的最佳匹配。

二分图:简单来说,如果图中点可以被分为两组,并且使得所有边都跨越组的边界,则这就是一个二分图。准确地说:把一个图的顶点划分为两个不相交集  U U 和 V V ,使得每一条边都分别连接 U U、 V V中的顶点。如果存在这样的划分,则此图为一个二分图。二分图的一个等价定义是:不含有「含奇数条边的环」的图。图 1 是一个二分图。为了清晰,我们以后都把它画成图 2 的形式。

匹配:在图论中,一个「匹配」(matching)是一个边的集合,其中任意两条边都没有公共顶点。例如,图 3、图 4 中红色的边就是图 2 的匹配。

      

我们定义匹配点、匹配边、未匹配点、非匹配边,它们的含义非常显然。例如图 3 中 1、4、5、7 为匹配点,其他顶点为未匹配点;1-5、4-7为匹配边,其他边为非匹配边。

最大匹配:一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。图 4 是一个最大匹配,它包含 4 条匹配边。

完美匹配:如果一个图的某个匹配中,所有的顶点都是匹配点,那么它就是一个完美匹配。图 4 是一个完美匹配。显然,完美匹配一定是最大匹配(完美匹配的任何一个点都已经匹配,添加一条新的匹配边一定会与已有的匹配边冲突)。但并非每个图都存在完美匹配。

举例来说:如下图所示,如果在某一对男孩和女孩之间存在相连的边,就意味着他们彼此喜欢。是否可能让所有男孩和女孩两两配对,使得每对儿都互相喜欢呢?图论中,这就是完美匹配问题。如果换一个说法:最多有多少互相喜欢的男孩/女孩可以配对儿?这就是最大匹配问题。


好了,二分图匹配是啥基本上就解释完了,下面开始氪题(下面就是我自己写的了)。


第一题    【游戏】

Time Limit 1s Memory Limit 128M

Description

lxhgww最近迷上了一款游戏,在游戏里,他拥有很多的装备,每种装备都有2个属性,这些属性的值用[1,10000]之间的数表示。当他使用某种装备时,他只能使用该装备的某一个属性。并且每种装备最多只能使用一次。 游戏进行到最后,lxhgww遇到了终极boss,这个终极boss很奇怪,攻击他的装备所使用的属性值必须从1开始连续递增地攻击,才能对boss产生伤害。也就是说一开始的时候,lxhgww只能使用某个属性值为1的装备攻击boss,然后只能使用某个属性值为2的装备攻击boss,然后只能使用某个属性值为3的装备攻击boss……以此类推。 现在lxhgww想知道他最多能连续攻击boss多少次?

 

Input

输入的第一行是一个整数N,表示lxhgww拥有N种装备 接下来N行,是对这N种装备的描述,每行2个数字,表示第i种装备的2个属性值

Output

输出一行,包括1个数字,表示lxhgww最多能连续攻击的次数。

Sample Input

3

1 2

3 2

4 5

Sample Output

2

Hint

对于30%的数据,保证N < =1000

对于100%的数据,保证N < =1000000

这道题其实就是裸的匈牙利算法(<--这是什么我就不解释了),因为每一把武器都有两种属性,但是我们最多只需要它的其中一种(有的武器可能我们根本用不上)。所以我们就把武器和攻击力进行一一匹配。

再看数据范围,很明显如果我们老老实实完整跑一遍匈牙利,是会超时的。反正他求的是连击数,所以当我们无法匹配时,连击就断了,就立即跳出循环。

上代码。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define in(x) scanf("%d",&x)
#define maxn 2000000+10//蜜汁数组 
using namespace std;
int n;
int a[maxn],b[maxn];
int ans;
int vis[maxn];
int f[maxn];
struct Mad{int v,next;
}e[maxn*2];
int k=1;
int head[maxn*2];void adde(int a,int b)
{e[k].next=head[a];		e[k].v=b;head[a]=k++;
}int find(int x)//进来的是武器编号 
{for(int i=head[x];i!=-1;i=e[i].next){if(!vis[i]){vis[i]=1;if(!f[i]||find(f[i]))//有没有匹配过当前的攻击力,如果匹配了,看看能不能把之前的武器换个攻击力匹配 {f[i]=x;return 1;}}}return 0;
}int main()
{//freopen("A.in","r",stdin);//freopen("A.out","w",stdout);memset(head,-1,sizeof(head));int x,y;in(n);for(int i=1;i<=n;i++){in(x);in(y);adde(x,i);//预处理adde(y,i);//建二分图}int i;for(i=1;i<=n;i++){if(!find(i)) break;//跳出循环 }printf("%d\n",i-1);return 0;
}

大家也看到了,我的数组开得大破天际,如果我按照题目要求开1000000+的话,最后几组数据的答案会蜜汁变大,如果有谁发现为什么,希望能告知一二,谢谢。

第二题 【部落战争】

Time Limit 1s Memory Limit 128M

Description

lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国的下部征战来获得更大的领土。A国是一个M*N的矩阵,其中某些地方是城镇,某些地方是高山深涧无人居住。lanzerb把自己的部落分成若干支军队,他们约定:1.每支军队可以从任意一个城镇出发,并只能从上往向下征战,不能回头。途中只能经过城镇,不能经过高山深涧。2.如果某个城镇被某支军队到过,则其他军队不能再去那个城镇了。3.每支军队都可以在任意一个城镇停止征战。4.所有军队都很奇怪,他们走的方法有点像国际象棋中的马。不过马每次只能走1*2的路线,而他们只能走R*C的路线。lanzerb的野心使得他的目标是统一全国,但是兵力的限制使得他们在配备人手时力不从心。假设他们每支军队都能顺利占领这支军队经过的所有城镇,请你帮lanzerb算算至少要多少支军队才能完成统一全国的大业。

Input

第一行包含4个整数M、N、R、C,意义见问题描述。接下来M行每行一个长度为N的字符串。如果某个字符是'.',表示这个地方是城镇;如果这个字符时'x',表示这个地方是高山深涧。

Output

输出一个整数,表示最少的军队个数。

Sample Input

3 3 1 2

...

.x.

...

 

Sample Output

4

Sample Input

5 4 1 1

....

..x.

...x

....

x...

Sample Output

5

 

Hint

30%数据有n,m<=10 r,c<=5  

60%数据有n,m<=25 r,c<=10  

100%数据保证n,m<=50 r,c<=10

这道题就不是裸的匈牙利问题了,不过需要这种算法(这TM不是废话吗)。我们一看题目和样例数据,会发现这道题其实不是标准二分图,那么我们首先要做的事就是建图,把能到的点都和当前点连接起来加一条边。
	in(M);in(n);in(R);in(C);for(int i=0;i<M;i++)for(int j=0;j<n;j++){cin>>s;if(s=='.') {v++;//记录点的个数m[i][j]=v;//标记点的顺序方便待会建边}}for(int i=0;i<M;i++)for(int j=0;j<n;j++){//有四种走法,大家不妨推推int x=m[i][j];if(i+R<M&&j+C<n)if(m[i+R][j+C]) adde(x,m[i+R][j+C]);if(i+C<M&&j+R<n)if(m[i+C][j+R]) adde(x,m[i+C][j+R]);if(i+R<M&&j-C>=0)if(m[i+R][j-C]) adde(x,m[i+R][j-C]);if(i+C<M&&j-R>=0)if(m[i+C][j-R]) adde(x,m[i+C][j-R]);}


然后我们会发现,这是那什么最短路径覆盖,他的解就是——点的个数-最大匹配数,对!Mad我们又要求最大匹配数,又是匈牙利算法!
<span style="color:#33cc00;">#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#define in(x) scanf("%d",&x)
#define maxn 100+10
using namespace std;
int M,n,R,C;
int v,ans;
int m[250*2][250*2];
int vis[5000*2];
int used[5000*2];
struct Mad{int v,next;
}e[5000*2];
int head[5000*2];
int k=1;void adde(int a,int b)
{e[k].v=b;e[k].next=head[a];head[a]=k++;
}int find(int x)
{for(int i=head[x];i!=-1;i=e[i].next){int v=e[i].v;if(!vis[v]){vis[v]=1;if(!used[v]||find(used[v])){used[v]=x;return 1;}}}return 0;
}int main()
{//freopen("C.in","r",stdin);//freopen("C.out","w",stdout);char s;memset(head,-1,sizeof(head));in(M);in(n);in(R);in(C);for(int i=0;i<M;i++)for(int j=0;j<n;j++){cin>>s;if(s=='.') {v++;m[i][j]=v;}}for(int i=0;i<M;i++)for(int j=0;j<n;j++){int x=m[i][j];if(i+R<M&&j+C<n)if(m[i+R][j+C]) adde(x,m[i+R][j+C]);if(i+C<M&&j+R<n)if(m[i+C][j+R]) adde(x,m[i+C][j+R]);if(i+R<M&&j-C>=0)if(m[i+R][j-C]) adde(x,m[i+R][j-C]);if(i+C<M&&j-R>=0)if(m[i+C][j-R]) adde(x,m[i+C][j-R]);}for(int i=1;i<=v;i++){memset(vis,0,sizeof(vis));ans+=find(i);}ans=v-ans;printf("%d\n",ans);return 0;
}</span>


好的,然后我们又发现我的数组大得离谱,因为我按照题目要求开数组Mad只过6组啊有木有!!!!!!!!!!!



ps.看帖回帖是种美德


更多推荐

BZOJ 2150+BZOJ 1854【二分图匹配】 两更+蜜汁数组(游戏+部落战争)

本文发布于:2024-03-06 16:02:09,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1715749.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:蜜汁   数组   战争   部落   游戏

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!