题目
n
封信依次编号为
Small John能提供一组信息:第
i
封信肯定不是装在信封
请编程帮助Small John,确定一定匹配的信和信封.
1≤n≤100
分析
这是存在性问题,有两种思路:
①枚举所有的情况,找情况交;
②枚举所有可能的单个匹配,假设某种情况存在,进行验证;
【思路①】treat,AC
为了使效率尽可能高,我们要尽可能找较少的情况.
这较少的情况中要包含所有的有效情况,也就是所有肯定匹配的边都要包含在内.
存在性问题往往跟最值问题有关,不难想到一个最大匹配中必定包含所有的肯定匹配的边,但是最大匹配中有些边可能不是一定匹配的.
而枚举所有的最大匹配应该也会超时.
但是最大匹配中不满足的边应该不会很多.
我们考虑随机扩展顺序,求出
T
个最大匹配,然后求交.
时间复杂度为
现在要考虑
T
的取值.
由于匈牙利算法的实际效率大概是
这个代码虽然是骗分的,但是
T=1000
可以AC.
然而经检验发现,当
T=5
,都可以AC,而且实测2ms,跑得贼快~
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <ctime>
#include <algorithm>
using namespace std;
const int N=128;
const int T=1000;
int n;
int p[N][N];
inline int read(void)
{
int x=0; char c=getchar();
for (;!isdigit(c);c=getchar());
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x;
}
int ran[N];
int ran2[N];
int fltor[N];
int used[N];
int link[N];
int ltor[N];
int hungery(int now)
{
for (int i=1;i<=n;i++)
if (!used[ran2[i]]&&p[now][ran2[i]])
{
used[ran2[i]]=1;
if (!link[ran2[i]]||hungery(link[ran2[i]]))
{
link[ran2[i]]=now;
return 1;
}
}
return 0;
}
int main(void)
{
int x,y; n=read();
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) p[i][j]=1;
for (;;)
{
x=read(),y=read();
if (!x&&!y) break;
p[x][y]=0;
}
srand(time(0));
for (int i=1;i<=n;i++) ran[i]=i;
for (int i=1;i<=n;i++) ran2[i]=i;
for (int times=1;times<=T;times++)
{
random_shuffle(ran+1,ran+n+1);
random_shuffle(ran2+1,ran2+n+1);
memset(link,0,sizeof link);
for (int i=1;i<=n;i++)
{
memset(used,0,sizeof used);
hungery(ran[i]);
}
for (int i=1;i<=n;i++)
if (link[i]) ltor[link[i]]=i;
if (times==1)
memmove(fltor,ltor,sizeof ltor);
else
for (int i=1;i<=n;i++)
if (~fltor[i]) fltor[i]=fltor[i]==ltor[i]?ltor[i]:-1;
}
int flag=0;
for (int i=1;i<=n;i++)
if (~fltor[i]) printf("%d %d\n",i,fltor[i]),flag=1;
if (!flag) printf("none\n");
return 0;
}
【思路②】hungery,AC
接下来考虑思路②.
根据之前的分析,一个最大匹配中必定包含所有的肯定匹配的边.
我们先枚举最大匹配的每一条边,然后假设它一定需要,试着删除它,看看能不能凑出新的匹配方案.
如果不行,说明这条边是一定匹配的.
时间复杂度为 O(n3) .
代码:不写了~
小结
判定性问题中一定存在性问题的思路:
①求所有的情况交;
②对所有的可能存在的情况,假设它不存在了,验证没有另外的方案.
另外,要存在性问题往往可以与最优性问题扯上关系.
还有就是用枚举法解决的问题,可以考虑多次随机代替.
而枚举法常用于最优性问题,这意味着多次随机可用于最优性问题.
重新整理一下最优性问题的解决策略:dp,贪心,随机化/枚举实现的检索,图论的一些方法,(二分)参数搜索.