題目鏈接:https://vjudge.net/contest/181019#problem/F
題意:給定一個n*n的矩陣,從左下至右上平行於對角線的斜線共2*n-1條(包括對角線),在每條斜線上選取一個出現的值,要求這2*n-1條斜線選取的值互不相同,求是否能選取,若不能,輸出NO,若能,輸出YES並按1~2*n-1的順序輸出每條斜線上選取的值。
思路:從左下至右上爲這些斜線編號爲1~2*n-1,將編號x與斜線x上出現的數值進行連線,求出最大匹配數是否爲2*n-1即可。注意數值較大,可以爲每個數賦一個較小的id值放置vis數組越界。
代碼如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstdlib>
#include<sstream>
#include<deque>
#include<stack>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int maxn = 1000 + 20;
const int maxt = 300 + 10;
const int mod = 10;
const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, -1, 1};
const int Dis[] = {-1, 1, -5, 5};
const int inf = 0x3f3f3f3f;
const int MOD = 1000;
int n, m, k;
int d[maxn][maxn];
int match[100000 + 10];//因match數組開小WA一次
bool vis[100000 + 10];//因vis數組開太小RE一次
vector<int> g[maxn];
map<int, int> id;
map<int, int> pos;
int ans[maxn];
bool dfs(int u){
int v;
int len = g[u].size();
for(int i = 0; i < len; ++i){
v = g[u][i];
if(vis[v]) continue;
vis[v] = true;
if(match[v] == -1 || dfs(match[v])){
match[v] = u;
ans[u] = v;//記錄每條斜線的當前匹配值
return true;
}
}
return false;
}
int main(){
scanf("%d", &n);
int xx = 610;
id.clear(); pos.clear();
memset(d, 0, sizeof d);
for(int i = 0; i < maxn; ++i) g[i].clear();
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= n; ++j){
scanf("%d",&d[i][j]);
if(id.find(d[i][j]) == id.end()){//d[i][j]的值太大,根據輸入順序爲其編號,防止RE
id[d[i][j]] = xx;
pos[xx++] = d[i][j];
}
}
}
int t = n;
int num = 1, x = 2 * n;
while(t >= 1){//遍歷每一條斜線,從左下至右上id編號依次爲1~2*n-1,將斜線上存在的數值id值與斜線id值連線
for(int i = t, j = 1; i <= n; ++i,++j){
if(t != 1){
g[num].push_back(id[d[i][j]]);
g[x - num].push_back(id[d[j][i]]);
}
else{
g[num].push_back(id[d[i][j]]);
}
}
++num; --t;
}
int cnt = 0;
bool ok = true;
memset(ans, 0, sizeof ans);
memset(match, -1, sizeof match);
for(int i = 1; i < x; ++i){//爲每一條斜線尋找匹配值
memset(vis, false, sizeof vis);
if(dfs(i)){
++cnt;
}
else{//若有某條斜線無匹配值,直接退出
ok = false; break;
}
}
if(!ok || cnt != 2 * n - 1){
printf("NO\n"); return 0;
}
printf("YES");
for(int i = 1; i < x; ++i){
printf(" %d", pos[ans[i]]);
}
printf("\n");
return 0;
}
/*
5
1000000000 1000000000 1000000000 900000000 210000000
1000000000 200000000 200000000 800000000 700000000
1000000000 200000000 300000000 300000000 700000000
1000000000 200000000 600000000 400000000 700000000
700000000 700000000 700000000 00000000 700000000
//1 2 6 4 3 8 9
4
1 1 1 9
1 2 2 8
1 2 4 4
1 2 6 5
5
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
3
1 1 1
2 2 4
3 1 1
*/