链接
http://acm.hdu.edu.cn/showproblem.php?pid=2819
题意
$n*n$ 的 $01$ 矩阵,任意交换两行或两列,可交换无限次,问是否可使矩阵对角线上都为 $1$,输出交换方案。
思路
要使矩阵对角线上都为 $1$,原矩阵必然每行每列都至少有一个 $1$,并且只交换行或只交换列最后都能使矩阵对角线上都为 $1$。
对于 $1$,行列连线,左为行,右为列,作二分图最大匹配,第 $i$ 行与第 $j$ 列匹配表示第 $j$ 列与第 $i$ 列交换可使 $i$ 行 $i$ 列为 $1$。
若匹配数等于 $n$,则有解。
每次交换,更新匹配,打印交换的列数。
更新最后必然得到第 $i$ 行匹配第 $i$ 列的图,即矩阵对角线上都为 $1$。
代码
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| #include <bits/stdc++.h> #define SZ(x) (int)(x).size() #define ALL(x) (x).begin(),(x).end() #define PB push_back #define EB emplace_back #define MP make_pair #define FI first #define SE second using namespace std; typedef double DB; typedef long long LL; typedef pair<int,int> PII; typedef vector<int> VI; typedef vector<PII> VPII;
const int N=105; int n,match[N<<1]; bool vis[N][N],st[N]; bool dfs(int u) { for(int v=1;v<=n;v++) { if(!vis[u][v]||st[v]) continue; st[v]=true; if(match[v+n]==-1||dfs(match[v+n])) { match[v+n]=u; match[u]=v+n; return true; } } return false; } int main() { int tot=0; while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { scanf("%d",&vis[i][j]); } for(int i=1;i<=n<<1;i++) match[i]=-1; int res=0; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) st[j]=false; if(dfs(i)) res++; } if(res!=n) puts("-1"); else { VPII ans; for(int i=1;i<=n;i++) { if(match[i]==i+n) continue; int j=match[i]; swap(match[match[i+n]],match[i]); swap(match[i+n],match[j]); ans.EB(i,j-n); } printf("%d\n",SZ(ans)); for(auto x:ans) printf("C %d %d\n",x.FI,x.SE); } } return 0; }
|