舞蹈链

http://poj.org/problem?id=3074

 

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include <time.h>
#include<math.h>
#include<string>
#include<vector>
#include<utility>
using namespace std;
const int N=500010;
const int M=1010;
const int INF=0x3f3f3f3f;
int U[N],D[N],L[N],R[N];
int X[N],C[N];///插入节点的横纵坐标
int S[M],A[M],H[M];///S[]每一列结点的数量,A[]答案,H[]头结点
int n,s,ansd;///n列数,s节点数,ansd
void init(int n)///初始化
{
    int pp=n;
    for(int i=0;i<=pp;i++)
     U[i]=i,D[i]=i,L[i]=i-1,R[i]=i+1;
    R[pp]=0,L[0]=pp;s=pp+1;///表里已经有n+1个节点了
    memset(S,0,sizeof(S));
    memset(H,-1,sizeof(H));
}
void DelCol(int c)///删除列
{
    L[R[c]]=L[c];R[L[c]]=R[c];
    for(int i=D[c];i!=c;i=D[i])///列上结点对应的行也要删除
    {
        for(int j=R[i];j!=i;j=R[j])
            U[D[j]]=U[j],D[U[j]]=D[j],--S[C[j]];///删除行列上的节点数也要改变
    }
}
void ResCol(int c)///增加列
{
    for(int i=U[c];i!=c;i=U[i])///列上结点对应的行也要增加,,,i=U[i]
    {
        for(int j=L[i];j!=i;j=L[j])
        {
            ++S[C[j]],U[D[j]]=j,D[U[j]]=j;///增加行列上的节点数也要改变
        }
    }
    L[R[c]]=c,R[L[c]]=c;
}
void AddNode(int r,int c)///增加节点
{
    ++S[c],C[++s]=c,X[s]=r;///行上的结点数增加,该节点是s节点
    D[s]=D[c],U[D[c]]=s,U[s]=c,D[c]=s;///当写这个的时候自己可以画个图看看
    if(H[r]<0)H[r]=L[s]=R[s]=s;///行中没有结点
    else  R[s]=R[H[r]],L[R[H[r]]]=s,L[s]=H[r],R[H[r]]=s;
}

bool dfs(int d)
{
    if(!R[0])///当只剩下0结点,说明找到了答案
    {
        ansd=d;return true;
    }
    int c=R[0];
    for(int i=R[0];i;i=R[i])if(S[i]<S[c])c=i;///找到列中结点数少
    DelCol(c);
    for(int i=D[c];i!=c;i=D[i])
    {
        A[d]=X[i];
        for(int j=R[i];j!=i;j=R[j])DelCol(C[j]);///删除C[j]这一行,,,,写成了j,,
        if(dfs(d+1))return true;
        for(int j=L[i];j!=i;j=L[j])ResCol(C[j]);///没找到恢复
    }
    ResCol(c);///没找到恢复
    return false;
}
int ans[10][10];
int encode(int a,int b,int c)
{
    return a*81+(b-1)*9+c;
}
void decode()
{
    int x,y,k;
    for(int i=0;i<ansd;i++)
    {
        int r=A[i];
        k=r%9;
        if(k==0)k=9;
        int num=(r-k)/9+1;
        int y=num%9;
        if(y==0)y=9;
        x=(num-y)/9+1;
        ans[x][y]=k;
    }

}
int main()
{
    string str;
	char ch;
	while(1) {

		cin>>str;
		if(str=="end") break;
		int flag = 0, mp[100][100];
		for(int i=1; i<=9; i++)
			for(int j=1; j<=9; j++) {
				ch = str[flag++];
				if(ch=='.') mp[i][j] = 0;
				else mp[i][j] = ch - '0';
			}
		init(9*9*4);///初始化

		for(int i=1; i<=9; i++)
			for(int j=1; j<=9; j++)
				for(int k=1; k<=9; k++)
					if(!mp[i][j] || mp[i][j]==k) {
					int t = encode(0,i,j);///第几个数
					int r = encode(0,t,k);///在第几行,,第一个数1~9...第81个数721~729
					///四个判断条件
					AddNode(r,t);///每个空只能填一个数
					AddNode(r,encode(1,i,k));///每一行1~9只能填一次
					AddNode(r,encode(2,j,k));///每一列1~9只能填一次
					AddNode(r,encode(3,(i-1)/3*3+(j+2)/3,k));///每一块1~9只能填一次
				}

		dfs(0);
		decode();
		if(ansd==0)
            printf("impossible\n");
        else
        {
            for(int i=1; i<=9; i++)
            {
                for(int j=1; j<=9; j++)
                {
                    printf("%d",ans[i][j]);
                }
            }
            printf("\n");
        }
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值