POJ1084 DLX 摧毁火柴棒

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>
using namespace std;
const int maxn=360000;
const int maxc=500;
const int maxr=500;
const int inf=0x3f3f3f3f;
int L[maxn], R[maxn], D[maxn], U[maxn], C[maxn];
int S[maxc], H[maxr], size;
int cnt,ans;
int relate[6] [100] [100];
int shift;
void Link(int r, int c)
{
    S[c]++; C[size]=c;
    U[size]=U[c]; D[U[c]]=size;
    D[size]=c; U[c]=size;
    if(H[r]==-1) H[r]=L[size]=R[size]=size;
    else {
        L[size]=L[H[r]]; R[L[H[r]]]=size;
        R[size]=H[r]; L[H[r]]=size;
    }
    size++;
}
void remove(int c){///顺着link将本列所有元素屏蔽
    for (int i=D[c]; i!=c; i=D[i])
        L[R[i]]=L[i], R[L[i]]=R[i];
}
void resume(int c){
    for (int i=U[c]; i!=c; i=U[i])
        L[R[i]]=R[L[i]]=i;
}
int h(){///用精确覆盖去估算剪枝,本题加A*为0Ms, 不加为79Ms。
    int ret=0;///不太理解,但是这个h()肯定小于剩余步数,因为先选择一列,
    ///然后找出所有和这列有关的行(你总得选某行摧毁这列吧),
    ///再摧毁所有选出的行能关联的列。用vis标记摧毁
    ///肯定比剩余步数小了吧。。。
    bool vis[maxc];
    memset (vis, false, sizeof(vis));
    for (int i=R[0]; i; i=R[i])
    {
        if(vis[i])continue;
        ret++;
        vis[i]=true;
        for (int j=D[i]; j!=i; j=D[j])
            for (int k=R[j]; k!=j; k=R[k])
                vis[C[k]]=true;
    }
    return ret;
}


void Dance(int k){                ///根据具体问题选择限制搜索深度或直接求解。
    cout<<"Dance: "<<k<<endl<<endl;
    for (int i=0; i<size; i++){
        cout<<"id: "<<i<<" up= "<<U[i]<<" down= "<<D[i]<<
        " left= "<<L[i]<<" right= "<<R[i]<<endl;
    }
    if(k+h()>=ans) return;
    if(!R[0]){
        if(k<ans)ans=k;
        cout<<endl<<endl<<"find!!! ans="<<ans<<endl<<endl;
        return;
    }
    int c=R[0];
    for (int i=R[0]; i; i=R[i])
        if(S[i]<S[c])c=i;///选择节点最少的一列
    for (int i=D[c]; i!=c; i=D[i]){///枚举节点最少列的所有节点,
                                    ///即枚举和此列有关的所有行,
                                    ///本题题意下即为枚举所有可以销毁此正方形的火柴
        remove(i);///屏蔽i号节点所在列,并且找出i号节点所在行,枚举该行上的所有节点,将他们所在列屏蔽
        ///本题下即屏蔽在拿掉一根火柴后销毁的正方形
        cout<<"remove: "<<i<<endl;
        for (int j=R[i]; j!=i; j=R[j]){
            remove(j);//
            cout<<"remove: "<<j<<endl;
        }

        Dance(k+1);

        for (int j=L[i]; j!=i; j=L[j]){
            resume(j);
            cout<<"resume: "<<j<<endl;
        }
        resume(i);
        cout<<"resume: "<<i<<endl;
    }
    return ;
}

void initL(int x){///col is 1~x,row start from 1
    for (int i=0; i<=x; ++i){
        S[i]=0;
        D[i]=U[i]=i;
        L[i+1]=i; R[i]=i+1;
    }///对列表头初始化
    R[x]=0;
    size=x+1;///真正的元素从m+1开始
    memset (H, -1, sizeof(H));
    ///mark每个位置的名字
}

void build (int totsize, int nowsize, int lastend){
    if (nowsize>totsize) return;
    int nowtotr=2*(totsize+2-nowsize)*(totsize+1-nowsize);
    int nowtotc=(totsize+1-nowsize)*(totsize+1-nowsize);
    int matchneed=nowsize*4;
    int mod=2*totsize+1-2*(totsize-nowsize);
    int sqrperrow=totsize-nowsize+1;
    int spanperrow=2*totsize+1;


    for (int i=0; i<nowtotc; i++){
        shift=(i/sqrperrow)*spanperrow + i%sqrperrow;
        for (int count=1; count<=matchneed; count++){
            relate[totsize][count+shift][i+1+lastend]=1;

            //cout<<"Square Size "<<totsize<<" row="<<
            //count + shift << " col="<<i+1+lastend<<endl;

            if (count<=nowsize || count>nowsize*3){
                relate[totsize][count+shift][i+1];
                if (count==nowsize)
                    shift+=totsize-nowsize;
            }
            else {

                if ((count-nowsize)%2==1)
                    shift+=nowsize-1;
                else
                {
                    shift+=totsize-nowsize;
                    if (count!=nowsize*3)
                        shift+=totsize;
                }
            }


        }
    }

    build(totsize, nowsize+1, lastend+nowtotc);
}



void printr0(int maxn){
    for (int i=0; i<=maxn; i++)
        cout<<"row0: R["<<i<<"]="<<R[i]<<endl;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
int n,m,testcase,nowsize, destroy, totr, totc, temp;
int hash[100];


for (int i=1;i<=5; i++)
    build(i, 1, 0);

scanf("%d", &testcase);
while (testcase--){
    memset(hash, 0, sizeof(hash));
	scanf("%d %d", &nowsize, &destroy);


	totr=2*nowsize*(nowsize+1); totc=0;

    for (int i=1; i<=nowsize; i++)
        totc+=i*i;

    initL(totc);

    for (int i=1; i<=totr; i++)
        for (int j=1; j<=totc; j++)
            if (relate[nowsize][i][j]==1){
                Link(i, j);
                //cout<<"init_row "<<i<<" linked to col "<<j<<endl;
            }

    //cout<<" Size="<<size<<endl<<endl<<endl;

    //printr0(totr);

    for (int i=1; i<=5; i++){
        //cout<<"init_s"<<i<<"="<<S[i]<<endl;
    }

	for (int i=0; i<destroy; i++){
        scanf("%d", &temp);
        for (int j=1; j<=totc; j++)
            if (relate[nowsize][temp][j]==1){
                if (hash[j]==0) {
                    remove(j);
                    hash[j]=1;
                    L[R[j]]=L[j];
                    R[L[j]]=R[j];
                    //cout<<"init_remove: "<<j<<endl;
                }

            }
	}
    ans=0x7ffffff1;
    Dance(0);

    printf("%d\n",ans);

}
return 0;
}

好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦好烦


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值