upcoj 1975 棋盘覆盖二分匹配+2107单调队列+1109

首先是A题,这题知道用二分做之后自己做了一遍,开始建图没用好思路,然后就想到了建图的方法,主要是二分匹配要注意的点是:2个集合。

确定两个集合之间的关系,而不要在一个集合上自身匹配。

然后就无限WA了,样例和自己列的数据都过了,死磕都WA     后来问肖太爷,他建图方法比我简单多了,我是一个一个枚举搜索来区分组的,他就直接找不相邻的直接分组了,囧囧。

 

给出自己的挫WA代码吧。好歹思路是对的- -,我已经debug好久了。。。

1975:

//最大匹配
#include<iostream>
#include<cstring>
using namespace std;
int dx[2]={0,-1};
int dy[2]={1,0};
int map[3100][3100];
int g[60][60];
int b[60][60];
int tmp[3100];
int num[60][60];
int flag[3100];
int n,m;int lx,ly;
int DFS(int x)
{

    for(int i=0;i<=ly;i++)
    {
        if(!flag[i]&&map[x][i])
        {
            flag[i]=1;
            if(tmp[i]==-1||DFS(tmp[i]))
            {
                tmp[i]=x;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int T,i,k,j,sum,count,x,y;
    cin>>T;
    while(T--)
    {
        cin>>n>>m;
        for(i=0;i<n;i++)
        for(j=0;j<m;j++)
        {
            cin>>g[i][j];
        }
        //建图
        memset(map,0,sizeof(map));
        memset(tmp,-1,sizeof(tmp));
        memset(b,0,sizeof(b));
        memset(num,0,sizeof(num));
        count=1;//第一个标记为1集合
        lx=-1;ly=-1;  //代表1 2 集合的下标
        for(i=0;i<n;i++)
        for(j=0;j<m;j++)
        {
            if(!g[i][j])
            {
                if(b[i][j]==0)//1为一个集合  -1为一个集合 0为空洞
                {
                    b[i][j]=count;       //初始化
                    lx++;num[i][j]=lx;   //num  记录i,j坐标的元素在其集合上的下标

                }
                for(k=0;k<2;k++)
                {
                    if(i+dx[k]>=0&&i+dx[k]<n&&j+dy[k]>=0&&j+dy[k]<m&&!g[i+dx[k]][j+dy[k]])
                    {
                            if(b[i+dx[k]][j+dy[k]]==0)
                            {
                                b[i+dx[k]][j+dy[k]]=-b[i][j];  //相邻2点集合必定不同
                                if(b[i+dx[k]][j+dy[k]]==1){lx++;num[i+dx[k]][j+dy[k]]=lx;}
                                else {ly++;num[i+dx[k]][j+dy[k]]=ly;}
                                //将不同集合的连续两点加入图中
                                x=num[i][j];y=num[i+dx[k]][j+dy[k]];
                                if(b[i][j]==1)
                                map[x][y]=1;
                                else
                                map[y][x]=1;
                            }
                    }
                }
            }
        }
        for(i=0;i<=lx;i++)
        {
            cout<<endl;
            for(j=0;j<=ly;j++)
            {
                cout<<map[i][j]<<' ';
            }
        }
        sum=0;
        for(i=0;i<=lx;i++)
        {
            memset(flag,0,sizeof(flag));
            sum+=DFS(i);
        }
        if(sum%2==1)
        cout<<"甲"<<endl;
        else
        cout<<"乙"<<endl;
        //cout<<sum<<endl;
    }
}


 

然后是肖的代码:

#include<stdio.h>
#include<algorithm>
#include<string.h>
#define N 2100
int a[60][60],f[N][N],link[N],v[N],ma[N][N],i,j,k,m,n,x,y,z,t,ans,t1,t2;
bool dfs(int x)
{
    int i,j;
    for (i=1;i<t1;i++)
    if (!v[i]&&f[x][i])
    {
        v[i]=1;
        if (link[i]==0||dfs(link[i]))
        {
            link[i]=x;return true;
        }
    }
    return false;
}
int main()
{
    scanf("%d",&t);
    while (t--)
    {
        memset(a,0,sizeof(a));
        memset(f,0,sizeof(f));
        memset(link,0,sizeof(link));
        memset(ma,0,sizeof(ma));
        scanf("%d%d",&n,&m);
        for (i=1;i<=n;i++)
         for (j=1;j<=m;j++)
          {
              scanf("%d",&a[i][j]);
              a[i][j]=a[i][j]^1;
          }
        t1=1,t2=1;
        for (i=1;i<=n;i++)
         for (j=1;j<=m;j++)
         {
             if ((i+j)%2==1&&a[i][j])ma[i][j]=t1++;
             if ((i+j)%2==0&&a[i][j])ma[i][j]=t2++;
         }
        for (i=1;i<=n;i++)
         for (j=1;j<=m;j++)
         if ((i+j)%2==0)
         {
             if (j>1&&a[i][j-1])f[ma[i][j]][ma[i][j-1]]=1;
             if (i>1&&a[i-1][j])f[ma[i][j]][ma[i-1][j]]=1;
             if (i<n&&a[i+1][j])f[ma[i][j]][ma[i+1][j]]=1;
             if (j<m&&a[i][j+1])f[ma[i][j]][ma[i][j+1]]=1;
         }
        int ans=0;
        for (i=1;i<t2;i++)
        {
            memset(v,0,sizeof(v));
            if (dfs(i))ans++;
        }
        if (ans%2==0)printf("ÒÒ\n");else printf("¼×\n");
    }
}


后面两题也很水,水题都过不了主要是分析的问题,分析问题太弱了- -

2107   这题主要是要控制好stack栈顶的进出,一般单调队列都需要注意这个问题,代码很容易理解

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int stack[1000005];
int a[1000005];
int c[1000005];
int main()
{
    int n,i,top,k,x;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    top=0;
    memset(stack,0,sizeof(stack));
    memset(c,0,sizeof(c));
    for(i=1;i<=n;i++)
    {
        while(top>0)
        {
            if(top>0&&stack[top]>=a[i])top--;
            else break;
        }
        if(top==0)c[i]=-1;
        else c[i]=stack[top];
        top++;
        stack[top]=a[i];
    }
    scanf("%d",&k);
    while(k--)
    {
        scanf("%d",&x);
        printf("%d\n",c[x]);
    }
    return 0;
}


1109 这题其实找规律就行了,用了点动态规划的思想。好好学DP啊。。。

#include<iostream>
#include<cstring>
using namespace std;
int dp[2][20];
int main()
{
    int n,j,k;
    cin>>n>>k;
    int sum;
    memset(dp,0,sizeof(dp));
    dp[0][1]=1;
    dp[1][1]=k-1;
    for(int i=2;i<=n-1;i++)//代表位置
    {
        dp[1][i]=dp[1][i-1]+dp[0][i-1];
        dp[0][i]=dp[1][i-1];

            dp[1][i]*=k-1;
            dp[0][i]*=1;
    }
    sum=dp[0][n-1]+dp[1][n-1];
    cout<<sum*(k-1)<<endl;
    return 0;
}


 

posted @ 2013-04-23 19:05  amourjun  阅读(185)  评论(0编辑  收藏  举报