题意: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;
}