codves 3052 多米诺 && codves 1022 覆盖

3052 多米诺
 
时间限制: 1 s
 空间限制: 256000 KB
 题目等级 : 钻石 Diamond
 
题目描述 Description

一个矩形可以划分成M*N个小正方形,其中有一些小正方形不能使用。一个多米诺骨牌占用两个相邻的小正方形。试问整个区域内最多可以不重叠地放多少个多米诺骨牌且不占用任何一个被标记为无法使用的小正方形。

输入描述 Input Description

第一行有两个用空格隔开的正整数M和N。

    第二行有一个正整数K,表示共有K个小正方形不能使用。输入数据保证K<=M*N。

    以下K行每行有两个用空格隔开的数X和Y,表示第X行的第Y个小正方形不能使用。

输出描述 Output Description

输出最多能放多少个多米诺骨牌。

样例输入 Sample Input

3 3

2

1 1

2 2

样例输出 Sample Output

3

数据范围及提示 Data Size & Hint

对于30%的数据,M=1;

    对于50%的数据,M<=2;

    对于70%的数据,M<=3;

    对于100%的数据,M<=50,N<=50。

#include<cstdio>
#include<cstring>
const int N=55;
int next[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int map[N][N],f[N*N][N*N];
int book[N*N];
int tag[N*N];
int n,m,k;
int p,q;
bool find(int x)
{
    for(int i=1;i<=q;i++)
    {
        if(f[x][i]&&(!book[i]))
        {
            book[i]=1;
            if(!tag[i]||(find(tag[i])))
            {
                tag[i]=x;
                return true;
            }
        }
    }
    return false;
}
int main()
{
    scanf("%d %d %d",&n,&m,&k);
    
    for(int i=1;i<=k;i++)
        scanf("%d %d",&p,&q),map[p][q]=-1;
    p=0,q=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(map[i][j]!=-1)
            {
                if((i+j)&1) map[i][j]=++p;
                else map[i][j]=++q;
            }
//    for(int i=1;i<=n;i++)
//    {
//        for(int j=1;j<=m;j++)
//            printf("%d ",map[i][j]);
//        printf("\n");
//    }
        
            
    int v,u;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(map[i][j]!=-1&&(i+j)&1)
                for(int k=0;k<4;k++)
                    {
                        v=i+next[k][0],u=j+next[k][1];
                        if(v>=1&&v<=n&&u>=1&&u<=m&&map[v][u]!=-1)
                            f[map[i][j]][map[v][u]]=1;            
                    }
//    for(int i=1;i<=p;i++)
//    {
//        for(int j=1;j<=q;j++)
//            printf("%d ",f[i][j]);
//        printf("\n");
//    }
    int ans=0;
    for(int i=1;i<=p;i++)
    {
        memset(book,0,sizeof(book));
        if(find(i)) ans++;
    }    
    printf("%d",ans);
    return 0;
}
View Code

解:预处理黑白染色,在连接奇偶间建边;

find函数要枚举p,q;

----------

 

1022 覆盖

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 大师 Master
 
 
题目描述 Description

有一个N×M的单位方格中,其中有些方格是水塘,其他方格是陆地。如果要用1×2的矩阵区覆盖(覆盖过程不容许有任何部分重叠)这个陆地,那么最多可以覆盖多少陆地面积。

 

输入描述 Input Description

输入文件的第一行是两个整数NM  (1<=NM<=100),第二行为一个整数K( K<=50),接下来的K行,每行两个整数X,Y表示K个水塘的行列位置。(1<=X<=N1<=Y<=M)。

 

输出描述 Output Description

输出所覆盖的最大面积块(1×2面积算一块)。

样例输入 Sample Input

4 4

6

1 1

1 4

2 2

4 1

4 2

4 4

样例输出 Sample Output

4

解:(同上)用邻接矩阵,5000*5000没MLE,666;

#include<cstdio>
#include<cstring>
const int N=101;
int next[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int map[N][N],f[(N*N)>>1][(N*N)>>1];
int book[(N*N)>>1];
int tag[(N*N)>>1];
int n,m,k;
int p,q;
bool find(int x)
{
    for(int i=1;i<=q;i++)
    {
        if(f[x][i]&&(!book[i]))
        {
            book[i]=1;
            if(!tag[i]||(find(tag[i])))
            {
                tag[i]=x;
                return true;
            }
        }
    }
    return false;
}
int main()
{
    scanf("%d %d %d",&n,&m,&k);
    
    for(int i=1;i<=k;i++)
        scanf("%d %d",&p,&q),map[p][q]=-1;
    p=0,q=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(map[i][j]!=-1)
            {
                if((i+j)&1) map[i][j]=++p;
                else map[i][j]=++q;
            }
//    for(int i=1;i<=n;i++)
//    {
//        for(int j=1;j<=m;j++)
//            printf("%d ",map[i][j]);
//        printf("\n");
//    }
        
            
    int v,u;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(map[i][j]!=-1&&(i+j)&1)
                for(int k=0;k<4;k++)
                    {
                        v=i+next[k][0],u=j+next[k][1];
                        if(v>=1&&v<=n&&u>=1&&u<=m&&map[v][u]!=-1)
                            f[map[i][j]][map[v][u]]=1;            
                    }
//    for(int i=1;i<=p;i++)
//    {
//        for(int j=1;j<=q;j++)
//            printf("%d ",f[i][j]);
//        printf("\n");
//    }
    int ans=0;
    for(int i=1;i<=p;i++)
    {
        memset(book,0,sizeof(book));
        if(find(i)) ans++;
    }    
    printf("%d",ans);
    return 0;
}
View Code

 

 

posted @ 2017-10-07 20:19  12fs  阅读(190)  评论(0编辑  收藏  举报