http://poj.org/problem?id=1691
题意:
给定一个大矩形,然后给出n个需要染色的小矩形的左上角的坐标,右下角的坐标以及该矩形要染得颜色,每个颜色对应的一把刷子。问将这些小矩形染完规定的颜色之后需要最少的刷子数。
要求:只当该小矩形的上边的矩形都染完色之后,该矩形才能染色,如果同一个刷子被使用多次也要计算进来;
思路:
首先根据一个矩形的所有上部分染完之后才能染色建立关系图,然后根据拓扑排序的理论,找入度为0的点开始染色,(因为入度为0 表明其上部的所有矩形都已经染色),dfs所有点求最小值。
注意这里画的边只是统计度数用的,而我们真正用来描述可行的边是根据经过该点之后的剩余点里面的入度为0的点时接下来要访问的点:
View Code
#include <cstdio> #include <cstring> #define maxn 17 using namespace std; const int inf = 0x7fffffff; struct node { int lx,ly; int rx,ry; int col; }p[maxn]; int map[maxn][maxn],deg[maxn]; bool vt[maxn]; int ans,n; void Buildmap() { int i,j; memset(deg,0,sizeof(deg)); memset(map,0,sizeof(map)); for (i = 0; i < n; ++i) { for (j = 0; j < n; ++j) { if (i != j && p[j].ly == p[i].ry && !(p[j].rx < p[i].lx || p[j].lx > p[i].rx))//建图的关键 { map[i][j] = 1; deg[j]++; } } } } void dfs(int dep,int col,int sum) { int i,j; if (sum > ans) return ; if (dep == n) { if (sum < ans) ans = sum; return ; } for (i = 0; i < n; ++i) { if (!vt[i] && deg[i] == 0)//每次去入度为0的点 { vt[i] = true; for (j = 0; j < n; ++j) { if (map[i][j]) deg[j]--; } if (p[i].col == col) dfs(dep + 1,col,sum); else dfs(dep + 1,p[i].col,sum + 1); vt[i] = false; for (j = 0; j < n; ++j) { if (map[i][j]) deg[j]++; } } } } int main() { //freopen("d.txt","r",stdin); int i,t; scanf("%d",&t); while (t--) { scanf("%d",&n); for (i = 0; i < n; ++i) scanf("%d%d%d%d%d",&p[i].ly,&p[i].lx,&p[i].ry,&p[i].rx,&p[i].col); ans = inf; Buildmap(); memset(vt,false,sizeof(vt)); dfs(0,0,0); printf("%d\n",ans); } return 0; }