题意

现有n*m的长方形网格,每个格子中写着一个数,并构成了[0,n*m)的排列。每次可以将一行循环平移x格,也可以将一列循环平移x格。给出初始状态,给出一个到达给定状态的方案。n*m<=10000,n,m>=2。


 

思考

发现存在一种方法,能够使任意三个方格进行顺时针或逆时针改变位置。其中有一个方格的行和列由剩余两个方格决定。

这样一来,我们可以将前n-1行排成有序的,只剩下最后一行是无序的。

通过第一张改变位置的方式,我们也可以将同一行的任意三个方格进行循环平移。这样可以将最后一行的前m-2个排成有序的,剩下的两个不一定有序。

这种方法虽然不能判断出是否能够达到有序状态,但是在随机情况下会以一定概率达到。因此可以重复打乱原始序列,进行多次判断。

总复杂度O(Tnm),T为随机次数。


 

代码

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef unsigned long long ull;
  4 const int maxn=1E2+5;
  5 int X[maxn*maxn],Y[maxn*maxn];
  6 int a[maxn][maxn],n,m,wait[maxn];
  7 ull seed=233;
  8 inline int R(int l,int r)
  9 {
 10     seed^=seed<<13;
 11     seed^=seed>>7;
 12     seed^=1;
 13     return seed%(r-l+1)+l;
 14 }
 15 struct note
 16 {
 17     int opt,x,y;
 18     note(int a=0,int b=0,int c=0)
 19     {
 20         opt=a,x=b,y=c;
 21     }
 22 };
 23 vector<note>ans;
 24 inline void swap(int x1,int y1,int x2,int y2,int x3,int y3)
 25 {
 26     swap(X[a[x1][y1]],X[a[x3][y3]]);
 27     swap(Y[a[x1][y1]],Y[a[x3][y3]]);
 28     swap(X[a[x1][y1]],X[a[x2][y2]]);
 29     swap(Y[a[x1][y1]],Y[a[x2][y2]]);
 30     swap(a[x1][y1],a[x3][y3]);
 31     swap(a[x3][y3],a[x2][y2]);
 32     int len1=y2-y1,len2=x2-x3;
 33     if(len1<0)
 34         len1+=m;
 35     if(len2<0)
 36         len2+=n;
 37     ans.push_back(note(1,x1,len1));
 38     ans.push_back(note(2,y2,len2));
 39     ans.push_back(note(1,x1,m-len1));
 40     ans.push_back(note(2,y2,n-len2));
 41 }
 42 inline void swapRow(int x,int y1,int y2,int y3)
 43 {
 44     swap(x,y1,x,y2,x-1,y2);
 45     swap(x,y1,x,y2,x-1,y2);
 46     swap(x,y3,x,y2,x-1,y2);
 47 }
 48 void out()
 49 {
 50     for(int i=1;i<=n;++i,cout<<endl)
 51         for(int j=1;j<=m;++j)
 52         {
 53             cout.width(4);
 54             cout<<a[i][j];
 55         }
 56 }
 57 void work()
 58 {
 59     for(int i=1;i<=n-1;++i)
 60     {
 61         for(int j=1;j<=m;++j)
 62         {
 63             int num=(i-1)*m+j-1;
 64             if(a[i][j]==num)
 65                 continue;
 66             if(i==X[num])
 67                 swap(X[num],Y[num],i,j,i+1,j);
 68             else if(j==Y[num])
 69                 swap(X[num],j==1?m:1,X[num],Y[num],i,j);
 70             else
 71             {
 72                 int x=X[num],y=Y[num];
 73                 swap(x,y,x,j,i,j);
 74                 swap(x,y,x,j,i,j);
 75             }
 76         }
 77     }
 78     for(int i=1;i<=m-2;++i)
 79     {
 80         int num=(n-1)*m+i-1;
 81         if(a[n][i]==num)
 82             continue;
 83         if(Y[num]==i+1)
 84             swapRow(n,i,i+1,i+2);
 85         else
 86         {
 87             int G=Y[num];
 88             swapRow(n,i,i+1,G);
 89             swapRow(n,i,i+1,G);
 90         }
 91     }
 92 }
 93 void row(int x,int y)
 94 {
 95     ans.push_back(note(1,x,y));
 96     for(int i=1;i<=m;++i)
 97         wait[i]=a[x][i-y>=1?i-y:i-y+m];
 98     for(int i=1;i<=m;++i)
 99         a[x][i]=wait[i],Y[wait[i]]=i;
100 }
101 void col(int x,int y)
102 {
103     ans.push_back(note(2,x,y));
104     for(int i=1;i<=n;++i)
105         wait[i]=a[i-y>=1?i-y:i-y+n][x];
106     for(int i=1;i<=n;++i)
107         a[i][x]=wait[i],X[wait[i]]=i;
108 }
109 bool check()
110 {
111     for(int i=1;i<=n;++i)
112         for(int j=1;j<=m;++j)
113             if(a[i][j]!=(i-1)*m+j-1)
114                 return false;
115     return true;
116 }
117 int main()
118 {
119     srand(time(0));
120     ios::sync_with_stdio(false);
121     cin>>n>>m;
122     for(int i=1;i<=n;++i)
123         for(int j=1;j<=m;++j)
124         {
125             cin>>a[i][j];
126             X[a[i][j]]=i,Y[a[i][j]]=j;
127         }
128     int T=10;
129     while(T--)
130     {
131         work();
132         if(check())
133             break;
134         int t=10;
135         row(n,1);
136     }
137     if(!check())
138     {
139         cout<<-1<<endl;
140         return 0;
141     }
142     cout<<ans.size()<<endl;
143     for(int i=0;i<ans.size();++i)
144         cout<<ans[i].opt<<" "<<ans[i].x<<" "<<ans[i].y<<endl;
145     return 0;
146 }
View Code

 NOTE:最好要多随机几行和几列,防止极端数据。

 posted on 2019-07-08 16:38  GreenDuck  阅读(136)  评论(0编辑  收藏  举报