您的位置:首页 > 其它

[BZOJ 1562][NOI 2009]变换序列(二分图匹配)

2015-02-22 19:49 218 查看

题目链接

http://www.lydsy.com/JudgeOnline/problem.php?id=1562

题目大意

有一个长为n的长为n的序列AA,对于任意的Ai,1<=i<=n,1<=Ai<=n,且对于任意的1<=i,j<=n,i!=j,Ai!=AjA_i,1<=i<=n,1<=A_i<=n,且对于任意的1<=i,j<=n,i!=j,A_i!=A_j。对其中每个元素进行加did_i modmod nn或者是减did_i加nn后modmod nn的操作后,变成一个新的序列TT,要你判断这样的TT是否存在,以及最小字典序的TT。

题目思路

如果只要判断合法性,这就是个裸的二分图匹配问题,将A中的每个AiA中的每个A_i与T中的数字(Ai+di)T中的数字(A_i+d_i) modmod nn,(Ai−di+n)(A_i-d_i+n) modmod nn连边,然后判断二分图是否能完全匹配即可。不过如果要求字典序最小的TT也很简单,我们只需要保证邻接表中的每条边按照它们的终点升序排序,那么在二分图匹配时,如果没有增广的情况,每个x侧点选择的y侧点一定都是最小的。我们再从x侧点的最后一个点开始,从后往前进行增广,便能使得前面的点找不到匹配的y侧点时,后面的点会由最小的y侧对应匹配点变成大一点点的匹配点,而前面的点就能选择更小的那个匹配点了,这样保证前面的点找到的匹配点比后面的点找到的匹配点更优,便能满足最小字典序的要求了(说起来很绕口额。。。大家自己意识流一下便能明白为什么这是正确的了)

然后很无脑地贡献了4发PE,坑爹的BZOJ居然不能输出行末空格和文末换行

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>

#define MAXE 1100000
#define MAXV 31000

using namespace std;

int n;
int pre[MAXV];
bool visit[MAXV];
vector<int>G[MAXV];

bool dfs(int u)
{
for(int i=0;i<(int)G[u].size();i++)
{
int v=G[u][i];
if(!visit[v])
{
visit[v]=true;
if(pre[v]==-1||dfs(pre[v]))
{
pre[v]=u;
pre[u]=v;
return true;
}
}
}
return false;
}

int main()
{
memset(pre,-1,sizeof(pre));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int d;
scanf("%d",&d);
int a=i-d,b=i+d;
if(a<=0) a+=n;
if(b>n) b-=n;
a+=n,b+=n; //与原有的1~n的数字区分开
if(a>b) swap(a,b); //保证a<b,这样邻接表里的边的终点才能是字典序
G[i].push_back(a),G[i].push_back(b);
}
for(int i=n;i>=1;i--) //注意是从后往前做二分图匹配
{
memset(visit,false,sizeof(visit));
if(!dfs(i))
{
printf("No Answer");
return 0;
}
}
for(int i=1;i<n;i++)
printf("%d ",pre[i]-n-1);
printf("%d",pre
-n-1);
//printf("\n");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: