您的位置:首页 > 其它

HDU5727

2016-07-27 16:36 274 查看
Problem : Necklace

Source : 2016 Multi-University Training Contest 1

Description : 有一串项链,有2*N颗珠子,珠子有阴阳之分,各一半,同种类型的珠子不能项链,但是现在又有一些规则:有些阳珠子和阴珠子在一起就会使得阳珠子变暗,问你最少会有多少颗阳珠子变暗。

Solution : 全排列枚举+二分图最大匹配。讲道理,一开始我并不知道是用二分图来做的。知道用二分图做又不知道如何建图,知道看到了网上有人说全排列,我才有了灵感,我们知道,阴阳珠子的位置都是不固定的,那么我们就枚举固定阴珠子的位置。然后每个位置看能不能放阳珠子,如果能放就连边。最后求出最大匹配是表示有几个位置的阳珠子不会暗淡。最后直接维护一个最值就好了。下面一张图:



由于我一开始看到的解题报告是“环排”,也就是环排列,这是一个优化,n的环排列是(n−1)!,因为是环,所以环可以旋转,如果旋转后的环同原来的环一样,那么这两个环就是一个环。因此,我们不让它旋转,也就是固定一个位置,这里我选择固定1这个位置,后面的数进行全排列就好了。但是这个题不用环排也可以过,直接全排列也行的,不过时间比较危险。开始我一直过不去样例,原因是我建图的时候是[阴->阳],而开始一输入的时候是[阳->阴]。因此我调了下输入的位置就过了。下图中的TLE是因为一个小小的优化没有写,那就是
if(!ans)break;
如果已经算出了最最小值,那么就不用再计算了,没有想到一个这样的语句居然能使TLE->187ms.

Code(C++) :

#include <stdio.h>
#include <string.h>

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>

#define MIN(a,b) ((a)>(b)? (b):(a))

using namespace std;

const int E=9+5;
const int F=E*E;

int N,M;
int edge[E][E];

int belong[E];
bool used[E];

vector<int> map[E];

void init_vector()
{
for(int i=0;i<E;i++)
map[i].clear();
}

bool dfs(int s)
{
for(int i=0;i<map[s].size();i++){
int end=map[s].at(i);
if(used[end])
continue;
used[end]=true;
if(belong[end]==-1||dfs(belong[end])){

d1fc
belong[end]=s;
return true;
}
}
return false;
}

int main()
{
//freopen("in.data","r",stdin);
while(~scanf("%d%d",&N,&M)){
memset(edge,true,sizeof(edge));
int a,b;
for(int i=0;i<M;i++)
scanf("%d%d",&a,&b),
edge[b][a]=false;
int ans=E;
int h[E]={
0,1,2,3,4,5,6,7,8,9,
};
do{
init_vector();
memset(belong,-1,sizeof(belong));
for(int i=1;i<=N;i++)
if(edge[h[1]][i]&&edge[h
][i])
map[1].push_back(i);
for(int j=2;j<=N;j++)
for(int i=1;i<=N;i++)
if(edge[h[j]][i]&&edge[h[j-1]][i])
map[j].push_back(i);
int sum=0;
for(int i=1;i<=N;i++){
memset(used,false,sizeof(used));
if(dfs(i))
++sum;
}
ans=MIN(N-sum,ans);
if(!ans)
break;
}while(next_permutation(h+2,h+N+1));    \\next_permutation(h+1,h+N+1)也可以

printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: