HDU 5386 Cover (2015年多校比赛第8场)

1.题目描述:点击打开链接

2.解题思路:本题利用逆向思维+贪心法解决。因为题目中已经告诉我们一定存在解,因此可以考虑贪心法的使用。这道题的妙处在于答案和初始矩阵是无关的,只和目标矩阵有关。因为不管初始矩阵长什么样,只要操作一样,加上解的存在性,得到的目标矩阵一定是相同的。接下来就是如何寻找操作序列。


假设最后一步操作执行后,我们得到了目标矩阵,由于所有操作都是对一整行或者一整列进行的,因此肯定有一行或者一列全部相同。这样,我们就可以从目标矩阵出发,逆着这个过程寻找,如果发现某一行或者一列全部相同, 那么就把对应的操作入队列,同时把这一行全部置零,本次操作也置零。


注意:本题的扫描顺序比较重要。我们规定从上往下,从左往右依次扫描,这样可以保证某些行或列置零后,剩余的行或列的非零元素依然连续。而且还有一个好处是当整个矩阵都置零后,剩余入队列的操作都是无关操作。

3.代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<functional>
using namespace std;

#define me(s)  memset(s,0,sizeof(s))
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P;

const int N=105;
int A[N][N];
int x[5*N],y[5*N],s[5*N][2];
int a[5*N];
int n,m;

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            scanf("%d",&A[i][j]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            scanf("%d",&A[i][j]);//由于目标矩阵才是本题的关键,因此只保存目标矩阵
        for(int i=1;i<=m;i++)
            scanf("%s%d%d",s[i],&x[i],&y[i]);
        int k=0;
        while(k<m)//大循环是m个操作是否都找到
        {
            for(int i=1;i<=m;i++)
            if(x[i])  //x[i]相当于标识符,大于0说明有对应的操作,等于0说明操作已经用过
            {
                if(s[i][0]=='L')//列操作
                {
                    int j;
                    for(j=1;j<=n;j++)//从上往下枚举行,看是否连续相等且都是大于0的
                        if(A[j][x[i]]&&A[j][x[i]]!=y[i])break;
                    if(j>n)//如果连续相等或连续都等于0
                    {
                        a[k++]=i;
                        for(j=1;j<=n;j++)
                            A[j][x[i]]=0;//将整列置零
                        x[i]=0;          //将操作标识符置零
                    }
                }
                else   //行操作同上
                {
                    int j;
                    for(j=1;j<=n;j++)
                        if(A[x[i]][j]&&A[x[i]][j]!=y[i])break;
                    if(j>n)
                    {
                        a[k++]=i;
                        for(j=1;j<=n;j++)
                            A[x[i]][j]=0;
                        x[i]=0;
                    }
                }
            }
        }
        for(int i=k-1;i>=0;i--)
            printf("%d%c",a[i]," \n"[i==0]);
    }
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值