codeforces-724

题目链接: http://codeforces.com/contest/724/problem/B

思路: 先把一步能够到达有序的情况枚举存在一个二维数组a里面。然后输入每一行 对每一行进行两两交换,交换后把对应的 a数组的状态加一。最后看是否存在到达n的状态。


#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<set>
#include<map>
#include<list>
#include<queue>
#include<deque>
#include<stack>
#include<string>
#include<vector>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<time.h>

using namespace std;
typedef long long LL;
const int INF=2e9+1e8;
const int MOD=1e9+7;
const int MAXSIZE=1e6+5;
const double eps=0.0000000001;
void fre()
{
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
}
#define memst(a,b) memset(a,b,sizeof(a))
#define fr(i,a,n) for(int i=a;i<n;i++)

int n,m,dp[405][21],tot;
int temp[22],ans[405];
void init()
{
    tot=0;
    memst(ans,0);
    for(int i=0; i<m; i++)
    {
        temp[i]=i+1;
        dp[tot][i]=i+1;
    }
    tot++;
    for(int i=0; i<m-1; i++)
        for(int j=i+1; j<m; j++)
        {
            for(int k=0; k<m; k++)
            {
                if(k==i) dp[tot][j]=temp[k];
                else if(k==j) dp[tot][i]=temp[k];
                else dp[tot][k]=temp[k];
            }
            tot++;
        }
        return ;
}
bool cmp(int pos,int *a)
{
    for(int i=0;i<m;i++) if(dp[pos][i]!=a[i]) return false;
    return true;
}
void bian(int *a)
{
    for(int i=0;i<tot;i++)
    {
        if(cmp(i,a)) ans[i]++;
    }
}
void add()
{
    int a[30];
    for(int i=0;i<m;i++) a[i]=temp[i];
    bian(a);
    for(int i=0; i<m-1; i++)
        for(int j=i+1; j<m; j++)
        {
            for(int k=0; k<m; k++)
            {
                if(k==i) a[j]=temp[k];
                else if(k==j) a[i]=temp[k];
                else a[k]=temp[k];
            }
            bian(a);
        }
}
bool get()
{
    for(int i=0;i<tot;i++) if(ans[i]==n) return true;
    return false;
}
int main()
{
    scanf("%d%d",&n,&m);
    init();
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            scanf("%d",&temp[j]);
        }
        add();
    }
    if(get()) printf("YES\n");
    else printf("NO\n");
    return 0;
}

// 复杂度  1e6  多一点

另一个写法请参考 这个 。这个方法更容易理解。

-----------------------------------------------------------------------分割线---------------------------------------------------------------------------------------------------------------------


 下面是 C 题 : http://codeforces.com/problemset/problem/722/C  

有两篇文章,目前看了模拟这个想法,写了 模拟 的,做法二是 扩展欧几里得 + 计算几何

模拟思路,预处理到边上的点的步数,对于一个点,往四个方向找,取最小值就可以了。

 

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>

using namespace std;
const int MAX=100005;
typedef long long int LL;

int a[MAX],b[MAX];
LL vis[MAX][4][4];
int n,m,k;
void init()
{
    memset(vis,-1,sizeof(vis));
    int tmp=0;
    int x=0,y=0;
    LL ti=0;
    while(1)
    {
        if(tmp==0)
        {
            if((n-x)+y==m) break;
            if((n-x)+y<m)
                vis[(n-x)+y][3][0]=ti+n-x,ti=ti+n-x,y=(n-x)+y,x=n,tmp=3;
            else
                vis[x+(m-y)][2][0]=ti+m-y,ti=ti+m-y,x=x+(m-y),y=m,tmp=1;
        }
        else if(tmp==1)
        {
            if(y-(n-x)==0) break;
            if(y>n-x)
                vis[y-(n-x)][3][1]=ti+(n-x),ti=ti+(n-x),y=y-(n-x),x=n,tmp=2;
            else
                vis[x+y][0][1]=ti+y,ti=ti+y,x=x+y,y=0,tmp=0;
        }
        else if(tmp==2)
        {
            if(x==y) break;
            if(x<y)
                vis[y-x][1][2]=ti+x,ti=ti+x,y=y-x,x=0,tmp=1;
            else
                vis[x-y][0][2]=ti+y,ti=ti+y,x=x-y,y=0,tmp=3;
        }
        else if(tmp==3)
        {
            if(y+x==m) break;
            if(y+x<m)
                vis[y+x][1][3]=ti+x,ti=ti+x,y=y+x,x=0,tmp=0;
            else
                vis[x-(m-y)][2][3]=ti+(m-y),ti=ti+(m-y),x=x-(m-y),y=m,tmp=2;
        }
    }
    return ;
}
int main()
{
    while(cin>>n>>m>>k)
    {
        for(int i=0; i<k; i++)
        {
            scanf("%d%d",&a[i],&b[i]);
        }
        init();
        for(int i=0; i<k; i++)
        {
            LL ans=1e18;
            if(a[i]==b[i])
            {
                printf("%d\n",a[i]);
                continue;
            }

            if((n-a[i])+b[i]>m)
            {
                if(vis[a[i]+(m-b[i])][2][3]!=-1)
                {
                    ans=min(ans,vis[a[i]+(m-b[i])][2][3]+m-b[i]);
                }
            }
            if((n-a[i])+b[i]<m)
            {
                if(vis[b[i]+n-a[i]][3][1]!=-1)
                {
                    ans=min(ans,vis[b[i]+n-a[i]][3][1]+n-a[i]);
                }
            }

            if(b[i]>n-a[i])
            {
                if(vis[b[i]-(n-a[i])][3][0]!=-1)
                {
                    ans=min(ans,vis[b[i]-(n-a[i])][3][0]+n-a[i]);
                }
            }
            if(b[i]<n-a[i])
            {
                if(vis[a[i]+b[i]][0][2]!=-1)
                {
                    ans=min(ans,vis[a[i]+b[i]][0][2]+b[i]);
                }
            }

            if(a[i]<b[i])
            {
                if(vis[b[i]-a[i]][1][3]!=-1)
                {
                    ans=min(ans,vis[b[i]-a[i]][1][3]+a[i]);
                }
            }
            if(a[i]>b[i])
            {
                if(vis[a[i]-b[i]][0][1]!=-1)
                {
                    ans=min(ans,vis[a[i]-b[i]][0][1]+b[i]);
                }
            }

            if(a[i]+b[i]>m)
            {
                if(vis[a[i]-(m-b[i])][2][0]!=-1)
                {
                    ans=min(ans,vis[a[i]-(m-b[i])][2][0]+(m-b[i]));
                }
            }
            if(a[i]+b[i]<m)
            {
                if(vis[a[i]+b[i]][1][2]!=-1)
                {
                    ans=min(ans,vis[a[i]+b[i]][1][2]+a[i]);
                }
            }
            if(ans!=1e18) printf("%I64d\n",ans);
            else printf("-1\n");
        }
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值