问题转化:
给出1个最多结点数为15的图,然后给出一些无向边,现在需要给这些边定向,使之不存在回路,输出最长路径的最小值。
(PS: 因为结点数很少,所以可能与集合的动归挂钩。)
书上说要对结点进行分层,规定如果两个结点之间有边相连,则不能放在同一层。
规定边的方向只能从所在层数较低的点指向所在层数较高的点。
那么最长路径包含的最少结点数就是 最少的层数。
因为上面的问题转化和一些约制使问题变得容易考虑了,仔细想想这样的问题转化是完全正确的。
然后书上说解法就是色数问题。
色数问题的解法书上是这么说的:
首先结点数比较少,我们可以用一个int型变量表示一个一些点的集合。
然后预处理找出所有“独立”的集合,“独立”的意思是 集合中任意两点之间没有边相邻。
(PS:有的题目处理就是这样的,枚举有关系的点集难,但是枚举矛盾或者无关的点集易)
然后进行分阶段的动态规划,给出一个初始状态S,不断地消去一个“独立”的子集S2。
dp[S]=min{dp[S^S2]+1}; (PS:异或就是消去了)
每消去一个就要加一。
这样求出的dp[S]就是最少层数。
最少层数可以理解为最长路径的最少结点数,就=最长路径最少边数+1,就=题目中所说的 the minimally possible length of themaximal alternating wait chain.+2。
/**==========================================
* This is a solution for ACM/ICPC problem
*
* @source:uva 1439 Exclusive Access 2
* @type: dp
* @author: wust_ysk
* @blog: http://blog.youkuaiyun.com/yskyskyer123
* @email: 2530094312@qq.com
*===========================================*/
#define REP(i,n) for(int i=0 ;i<(n) ;i++)
#define ysk(x) (1<<(x))
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF =0x3f3f3f3f;
const int n=15,maxn= 15;
const int maxm= 100;
int m;
bool G[maxn+4][maxn+4],ind[ysk(maxn)+4];
int dp[ysk(maxn)+4],best[ysk(maxn)+4],label[maxn+4];
int u[maxm+3],v[maxm+3];
int ed;
bool independence(int s)
{
REP(i,n) if(ysk(i)&s)
{
REP(j,n) if(ysk(j)&s)
{
if(i!=j&&G[i][j]) return false;
}
}
return true;
}
void getind()
{
for(int s=ed;s>0;s=(s-1)&ed )
{
ind[s]=independence(s);
}
}
int DP(int s)
{
if(~dp[s]) return dp[s];
if(!s) return dp[s]=0;
dp[s]=INF;
for( int s2=s;s2>0;s2=(s2-1)&s ) if(ind[s2])
{
int tmp=DP(s^s2)+1;
if(tmp<dp[s])
{
dp[s]=tmp;
best[s]=s2;
}
}
return dp[s];
}
void color(int &s,int k )
{
REP(i,n) if(s&ysk(i))
{
label[i]=k;
}
s=s^best[s];
}
int main()
{
while(~scanf("%d",&m))
{
char ch1,ch2;
int x,y;
memset(G,0,sizeof G);
ed=0;
REP(i,m)
{
scanf(" %c %c",&ch1,&ch2);
u[i]=x=ch1-'L';
v[i]=y=ch2-'L';
G[x][y]=G[y][x]=1;
ed|=ysk(x);
ed|=ysk(y);
}
getind();
memset(dp,-1,(ed+1)*sizeof dp[0]);
int ans=DP(ed);
printf("%d\n",ans-2);
int s=ed,k=0;
while(s)
{
color(s,k++);
}
REP(i,m)
{
int x=u[i];
int y=v[i];
if(label[x]>label[y]) swap(x,y);
printf("%c %c\n",x+'L',y+'L');
}
}
return 0;
}