poj1691(状态压缩,树型DP)

1.先说下我自己的思路:根据题目的特点:题目要求先刷上方的矩形,因此可以用图结构来描述这种约束,若A在B的下方,则连接A到B的有向边。然后可以把当前可以刷的最上层的顶点做为状态curState,times[curState]表示在状态curState下的最少刷的次数,则在状态curState下可以有多种决策,可以用选不同颜色的矩形刷(当然选择了一种颜色后就尽可能的多刷),当然最上层的顶点可能有相同颜色的顶点,这时可以同时刷。记取种i种颜色刷后的状态为nextState[i],则状态方程可表示为times[curState]=min { times[ nextState[i] ] }+1;


2.其实还有一种更好的思路(队友想出的),时间和空间都应该要少一些。和我的相反,它用的是bfs+状态压缩+记忆化。思路是这样的,用当前染色情况作为状态,每次从队列里弹出一个状态,重新构图(当然我我DFS也是要构图的)对颜色循环,选择入度为0的进行染色,得到下一状态。(按照黑书上说的话:他的是递推的,而我的是递归的)。而这个题是刚好满足bfs性质的,第一次到达该状态的肯定是最短的路径,也就是最少的步数,因为第一次到达全部染色的状态时就直接退出。


3.自己思路的代码(刚开始时写得很顺后来发现了致命的错误,就是染色会破坏图的结构,准确的讲是入度与出度。后来终于找到了之前认为不可行的方案,在递归里开数组,每次都重新构图,自己以为是会超内存的,结果也还好才880K,0MS.不过建议大家用第二种思路写。毕竟学习得法的目地就是为了提高时空效率,简化问题。


#include<cstring>
#include<cmath>
#include<cstdio>
#include<iostream>
using namespace std;
//   freopen("data.in","r",stdin);

#define N 15
#define STATE 32770//

int times[STATE];
bool mat[N][N];

int color[N];
struct Rect
{
    int x1,y1,x2,y2;
} rect[N];
int n;

struct Node
{
    int vex;
    Node *next;
    Node(int v):vex(v),next(NULL) {}
    void add(int v)
    {
        Node *pre,*cur;
        for(pre=this,cur=next; cur!=NULL; pre=cur,cur=cur->next)
        {
            if(cur->vex==v)return;
        }
         pre->next=new Node(v);
    }
};

void createGraph(int *in,int *out)
{
    cin>>n;
    for(int i=0; i<n; i++)
    {
        cin>>rect[i].y1>>rect[i].x1>>rect[i].y2>>rect[i].x2>>color[i];
    }

    for(int i=0;i<n;i++)in[i]=out[i]=0;//
    memset(mat,0,sizeof(mat));

    for(int i=0; i<n; i++)
    {
        for(int j=0; j<n; j++)
        {
            if(j!=i)
            {
                bool c1=rect[i].y2==rect[j].y1&&rect[i].y1<rect[j].y1;
                bool c2=rect[i].x1>rect[j].x1&&rect[i].x1<rect[j].x2;
                bool c3=rect[i].x2>rect[j].x1&&rect[i].x2<rect[j].x2;
                bool c4=rect[i].x1<=rect[j].x1&&rect[i].x2>=rect[j].x2;//
                if(c1&&(c2||c3||c4))
                {
                    mat[i][j]=true;
                    out[i]++;
                    in[j]++;
                }
            }
        }
    }
}
void rebuild(int u,int *in,int *out)
{
    for(int i=0; i<n; i++)
    {
        if(mat[u][i])
        {
            out[u]++,in[i]++;
            rebuild(i,in,out);
        }
    }
}
int traverse(int u,int *tIn,int *tOut)
{
    int state=0;
    for(int i=0; i<n; i++)
    {
        if(mat[u][i])
        {
            tOut[u]--;
            tIn[i]--;
            if(color[i]==color[u])
            {
                if(!tIn[i])state|=traverse(i,tIn,tOut);
            }
            else
            {
                if(!tIn[i])state|=(1<<i);
            }
        }
    }
    return state;
}

int dfs(int curState)//!!end
{
    if(times[curState]<N)return times[curState];
    else
    {
        int tmpState=curState,node=0;

        Node *yes=new Node(-1);
        Node *nodes=new Node(-1);
        while(tmpState)
        {
            if(tmpState&1)//
            {
                (* yes).add(color[node]);
                (*nodes).add(node);
            }
            tmpState>>=1;
            node++;
        }

        int in[N],out[N];
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        for(Node *tNode=nodes->next; tNode!=NULL; tNode=tNode->next)
        {
            rebuild(tNode->vex,in,out);
        }

        int tIn[N],tOut[N];//
        for(Node *tColor=yes->next; tColor!=NULL; tColor=tColor->next)
        {
            memcpy(tIn,in,n*sizeof(int));//
            memcpy(tOut,out,n*sizeof(int));

            int nextState=curState;
            for(Node *tNode=nodes->next; tNode!=NULL; tNode=tNode->next)
            {
                if(color[tNode->vex]==tColor->vex)
                {
                    nextState^=(1<<tNode->vex);
                    nextState|=traverse(tNode->vex,tIn,tOut);
                }
            }
            times[curState]=min(times[curState],dfs(nextState)+1);
        }
        return times[curState];
    }
}


int main()
{
    int in[N],out[N];
 //   freopen("data.in","r",stdin);
    int Case;
    cin>>Case;
    while(Case--)
    {
        createGraph(in,out);

        fill(times,times+STATE,N+1);//
        times[0]=0;
        int state=0;
        for(int i=0; i<n; i++)
        {
            if(in[i]==0)state+=(1<<i);
            if(out[i]==0)times[1<<i]=1;//
        }

        dfs(state);
        cout<<times[state]<<endl;
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值