题目大意:
对于给定的一个数列 a[n] 如果能找到 a[n] 的一种排列使得每个对于位置 i 的数 a[i] 满足 a[i] = i - 1 或者 a[i] = n - 1则输出"yes", 否则输出“no"
大致思路:
将左边和右边都分 n 个点, 代表左边(输入的a[i]的排列)
首先对于左边每个位置 i 的a[i] 与右边(可能的最终排列)的n个点连边
对于左边的点 k 与右边的编号分别 a[k] + 1 和 n - a[k] 的点连边然后寻找最大匹配,直接用匈牙利算法即可
如果最大匹配数是n就输出 yes 否则输出 no
代码如下:
Result : Accepted Memory : 0 KB Time : 109 ms
/*
* Author: Gatevin
* Created Time: 2014/8/3 14:09:34
* File Name: test.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
int t;
int n;
int a[10010];
const int maxn = 10010;
vector <int> g[maxn];
int from[maxn], tot;
bool use[maxn];
bool match(int x)
{
for(int i = 0; i < g[x].size(); i++)
{
if(!use[g[x][i]])
{
use[g[x][i]] = true;
if(from[g[x][i]] == -1 || match(from[g[x][i]]))
{
from[g[x][i]] = x;
return true;
}
}
}
return false;
}
int hungary()
{
tot = 0;
memset(from, 255, sizeof(from));
for(int i = 1; i <= n; i++)
{
memset(use, 0, sizeof(use));
if(match(i))
++tot;
}
return tot;
}
int main()
{
scanf("%d",&t);
bool flag = false;
for(int cas = 1; cas <= t; cas++)
{
scanf("%d",&n);
flag = false;
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
if(a[i] >= n)
{
flag = true;
}
g[i].push_back(a[i] + 1);
g[i].push_back(n - a[i]);
}
if(flag)
{
printf("Case %d: no\n",cas);
for(int i = 1; i <= n; i++)
{
if(!g[i].empty())
{
g[i].clear();
}
}
continue;
}
int ans = hungary();
if(ans == n)
{
printf("Case %d: yes\n",cas);
}
else
{
printf("Case %d: no\n",cas);
}
for(int i = 1; i <= n; i++)
{
if(!g[i].empty())
{
g[i].clear();
}
}
}
return 0;
}
当然还可以用YY的做法
对于右边每个点,用b[n]表示其可以与左边的点匹配的数量, 如果所有的右边的点可以与左边的点的匹配数量都是2就输出”yes",否则输出 “no"
cyl这个YY帝的做法:
Result : Accepted Memory : 0 KB Time : 36 ms
/*
* Author:
* Indestinee
* Date:
* 2014.08.03
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define cls(a) memset(a,0,sizeof(a))
#define rise(i,a,b) for(i=a;i<=b;i++)
#define fall(i,a,b) for(i=a;i>=b;i--)
int cas, T, i, n, a, cnt[10001];
bool flag;
int main()
{
cin >> cas;
rise( T , 1 , cas )
{
flag = true;
cin >> n;
cls( cnt );
rise( i , 1 , n )
{
scanf( "%d" , &a );
cnt[min(a,(n-1-a))] ++;
}
fall( i , ( n - 1 ) / 2 - 1 , 0 ) if( cnt[i] != 2 )
{
flag = false;
break;
}
if( n % 2 && cnt[n/2] != 1 ) flag = false;
if( n % 2 == 0 && cnt[n/2-1] != 2 ) flag = false;
cout << "Case " << T << ": ";
if( !flag ) cout << "no" << endl;
else cout << "yes" << endl;
}
return 0;
}