题目大意:
对于给定的一个数列 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; }
对于右边每个点,用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; }