题意:n*n的01矩阵,告诉你n-1个1的位置.其余位置都为0.
操作:交换任意两行或者任意两列.
n<=1e3.输出操作序列,使得n-1个1的都在主对线以下.
虽然是交换任意行和任意列,原本在同一列或者同一行上的1,操作后还是在同行同列.
那么n-1个1都在主对角线之下,说明包括主对线线及以上不能有1存在.
设t[j]为第j列上有多少个1. 现在通过列交换 将矩阵变为 t[1]>=t[2]>=...>=t[n]的形式
若存在a[i][j]=1 (i<=j) 那么找到一个没有换过的行k 并且a[k][j]==0 交换(i,k)这两行,
然后就可以不用再考虑第k行,因为,a[k][j]==1,k>j , 若a[k][p]==1 因为k>j>p 前面也满足.最多交换n-1次.
操作:交换任意两行或者任意两列.
n<=1e3.输出操作序列,使得n-1个1的都在主对线以下.
虽然是交换任意行和任意列,原本在同一列或者同一行上的1,操作后还是在同行同列.
那么n-1个1都在主对角线之下,说明包括主对线线及以上不能有1存在.
设t[j]为第j列上有多少个1. 现在通过列交换 将矩阵变为 t[1]>=t[2]>=...>=t[n]的形式
若存在a[i][j]=1 (i<=j) 那么找到一个没有换过的行k 并且a[k][j]==0 交换(i,k)这两行,
然后就可以不用再考虑第k行,因为,a[k][j]==1,k>j , 若a[k][p]==1 因为k>j>p 前面也满足.最多交换n-1次.
官方解, 因为只有n-1个1,那么找到一个空列j,把j扔到最后一列, 在找到一个非0行k,把k扔到最后一行.
那么现在可以不考虑第n行和第n列,并且1的个数<=n-2,问题变为(n-1)*(n-1) 放n-2个1的方法.
#include <bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; typedef pair<int,int> ii; const int N=1e3+5; struct node{ int col,id; }p[N]; bool cmp(node a,node b) { return a.col>b.col; } int n,a[N][N],now[N];//now[id]现在在第几列. vector<ii> res[3]; int mk[N]; int main() { ios::sync_with_stdio(false); cin.tie(0); cin>>n; int x,y; rep(i,1,n) now[i]=i; rep(i,1,n-1) { cin>>x>>y; a[x][y]=1; } rep(j,1,n) rep(i,1,n) p[j].col+=a[i][j],p[j].id=j; sort(p+1,p+1+n,cmp); rep(j,1,n) { if(j==now[p[j].id]) continue; res[2].push_back(ii(j,now[p[j].id])); rep(k,1,n) swap(a[k][j],a[k][now[p[j].id]]); rep(k,1,n) if(now[k]==j) { now[k]=now[p[j].id]; now[p[j].id]=j; break; } } int m=n; for(int j=n-1;j>=1;j--) { for(int i=1;i<=j;i++) { if(a[i][j]==1) { for(int k=j+1;k<=n;k++) if(!mk[k]&&a[k][j]==0) { mk[k]=true; m=k; break; } res[1].push_back(ii(i,m)); //O(n*n) for(int k=1;k<=n;k++) swap(a[i][k],a[m][k]); } } } cout<<res[1].size()+res[2].size()<<'\n'; for(int i=2;i>=1;i--) for(int j=0;j<res[i].size();j++) cout<<i<<' '<<res[i][j].first<<' '<<res[i][j].second<<'\n'; return 0; } /* 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 */
大佬のcode
//Copyright @ 2012, Chow-Shing Shih, All rights reserved. #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <vector> #include <list> #include <set> #include <map> #include <stack> #include <queue> #include <ctime> #include <utility> #include <iostream> #include <cmath> #define rep(i, n) for (int i = 1; i <= n; ++i) #define REP(i, n) for (int i = 0; i < n; ++i) #define INF 0x7fffffff #define MP(x, y) (make_pair(x, y)) #define pb(x) push_back(x) #define clr(a, b) memset(a, b, sizeof(a)) using namespace std; typedef long long llu; inline int Lowbit(int i){return i & (-i);} inline void read(int &n) { char c; for (c = getchar(); !(c >= '0' && c <= '9'); c = getchar()); n = c - '0'; for (c = getchar(); c >= '0' && c <= '9'; c = getchar()) n = n * 10 + c - '0'; } int tot, N, a[2000][2000], x, y; vector <pair<int, pair<int, int> > > ans; int main() { scanf("%d", &N); for (int i = 1; i < N; ++i) { scanf("%d%d", &x, &y); a[x][y] = 1; } while (N > 1) { int j; for (j = 1; j <= N; ++j) { int tot = 0; for (int i = 1; i <= N; ++i) tot += a[i][j]; if (tot == 0)break; } if (j != N && j) ans.push_back(make_pair(2, make_pair(j, N))); for (int i = 1; i <= N; ++i) a[i][j] = a[i][N], a[i][N] = 0; int i; for (i = N; i; i--) { int tot = 0; for (int j = 1; j <= N; ++j) tot += a[i][j]; if (tot) break; } if (i != N && i) ans.push_back(make_pair(1, make_pair(i, N))); for (int j = 1; j <= N; ++j) a[N + 1][j] = a[i][j], a[i][j] = a[N][j], a[N][j] = a[N + 1][j]; N--; } printf("%d\n", ans.size()); for (int i = 0; i < ans.size(); ++i) printf("%d %d %d\n", ans[i].first, ans[i].second.first, ans[i].second.second); return 0; }