ACM-ICPC North America Qualifier Contest 2018 L. Superdoku

题目:

Alice and Bob are big fans of math. In particular, they are very excited about playing games that are related to numbers. Whenever they see a puzzle like Sudoku, they cannot stop themselves from solving it. The objective of Sudoku is to fill a 9×9 grid with digits so that each column, each row, and each of the nine (3×3) subgrids that compose the grid (also called "boxes", "blocks", or "regions") contains all of the digits from 1 to 9. The puzzle setter provides a partially completed grid, which for a well-posed puzzle has a single solution.

After many years of solving Sudoku problems, Alice and Bob are tired of Sudoku. They have been trying to develop a harder variation of Sudoku, which they are calling Superdoku. In Superdoku, the grid is bigger –n×n instead of just 9×9. However, the "block" constraints are impossible to formulate when there are no further constraints on n. Therefore, there are no block constraints in Superdoku. Instead, the goal is simply to make sure that each column and each row in the grid contains all of the integers from 1 to n. After playing for a while in the standard way (where any of the grid cells may have previously been filled in), they decide that the game is too difficult and they want to simplify it. Therefore, they decide to make the initial grid further constrained. They constrain the board by filling in the first k rows completely.

Alice and Bob both believe that Superdoku is solvable. However, since nn could be very big, it may still take a long time to figure out a solution. They don't want to spend too much time on this single game, so they are asking for your help!

Input
The input consists of a single test case. The first line lists two space-separated integers 1≤n≤100and 0≤k≤n, denoting the size of the grid (n×n) and the number of rows k that are already filled in. Each of the following kk lines contains nn space-separated integers, denoting the first kk given rows. Allintegers in these kk lines are between 1 and n.

Output
Output either "yes" or "no" on the first line, indicating if there is a solution. If there is no solution, do not output anything more. If there is a solution, output nn more lines, each containing n space-separated integers, representing a solution. If there are multiple solutions, output any one of them.

本题答案不唯一,符合要求的答案均正确

样例输入1
4 2
1 2 3 4
2 3 4 1
样例输出1
yes
1 2 3 4
2 3 4 1
3 4 1 2
4 1 2 3
样例输入2
4 2
1 2 3 4
2 2 2 2
样例输出2
no

题意:创建一个新的数独方式,给出一个n*n数独,每行是1~n的数,每列是1~n的数,给出前k行,问是否可以完成这个数独,可以输出任意一个完整的数独,不可以输出"no"。

思路:先判断前k行是否可行,并标记每个数的行数,列数出现情况(下一次不能出现),在剩下的k+1~n行遍历,每行都是1~n出现一次(所以现在其实可以不用考虑每个数的行标记)。二分图匹配,二分图的一边是1~n的数, 另一边是1~n列。只要跑下匈牙利算法即可,只要稍微改动判定条件。

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f 
using namespace std;
typedef long long ll;
const int maxn=150;
bool he[150][150],li[150][150];
int g[150][150],used[150],mat[150],n,k,flag;
//g[i][j]记录 第i行第j列的数,he[i][j]是数字i第j行是否出现.
//li[i][j]是数字i第j列是否出现。mat[i]是第i列匹配的数字 
bool dfs(int x,int u)//匈牙利算法 
{//x是行数,u是数字 
    for(int y=1;y<=n;y++)
    {
        if(!used[y]&&li[u][y]==0)//该列没有出现过u 
        {
            used[y]=1; 
            if(!mat[y]||dfs(x,mat[y]))//可以匹配 
            {
                li[mat[y]][y]=0;//该列之前的匹配取消 
                li[u][y]=1;//标记该列改为u 
                g[x][y]=u;
                mat[y]=u;
                return true; 
            }
        }
    }
    return false;
}

int main()
{
    flag=0;
    memset(he,0,sizeof(he));
    memset(li,0,sizeof(li));
    memset(g,0,sizeof(g));
    scanf("%d%d",&n,&k);
    for(int i=1;i<=k;i++)
    {
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&g[i][j]);
            if(he[g[i][j]][i]||li[g[i][j]][j])//给出的k行不符合,标记 
                flag=1;
            he[g[i][j]][i]=1;
            li[g[i][j]][j]=1;
        }
    }
    if(flag)
        printf("no
");
    else
    {
        for(int i=k+1;i<=n;i++)//每行跑一遍二分图匹配 
        {
            memset(mat,0,sizeof(mat));
            for(int u=1;u<=n;u++)
            {
                memset(used,0,sizeof(used));
                if(!dfs(i,u))//不能匹配标记,好像这里是没用的,因为前k行符合,就一定有答案 
                {
                    flag=1;
                    break;
                }        
            }
            if(flag)
                break;    
        }
        if(flag)
            printf("no
");
        else
        {
            printf("yes
");
            for(int i=1;i<=n;i++)
            {
                printf("%d",g[i][1]);
                for(int j=2;j<=n;j++)
                    printf(" %d",g[i][j]);
                printf("
");    
            }    
        } 
    }
    return 0;
}
原文地址:https://www.cnblogs.com/xiongtao/p/11264294.html