大致题意:给定n个进程和它所需的两个资源,对于每个进程,让你确定它的调用两个资源的先后顺序,使得所有进程的总时间最短
(因为进程是可以并行的,比如“先P后Q”的进程和“先P后R”的进程可以并行,但“先P后Q”的进程和“先Q后R”的进程却不能
等待链:等待链是一个局部概念,表示所有约束的一部分组成的有向链,如R0->R1->R2表示资源R0完成后,才能完成R1,然后是R2
题解:关键是理解题目中等待链的概念。把每个进程看成无向边,连接它的两个资源;现在要把无向边定向,使最长等待链最短。
问题转化为,给定一个无向图,让你给边定向,使最长链最短。
图形结构不好做,还是要转化为树形结构。做了一个整体性的转化:把结点分成p层,从左到右编号0,1,2...,使得同层结点之间没有边。对任意一条边u-v,定向“从小编号到大编号”
然后就是“结点分层的问题”,可以参考“图的染色”问题的做法
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=100+5,C=15,all=1<<15; int n; int a1[N],a2[N]; bool g[C][C]; int f[all]; int pre[all]; bool ok[all]; int pos[C]; int main() { while(cin>>n){ memset(g,0,sizeof g); char a,b; for(int i=1;i<=n;i++){ cin>>a>>b; a1[i]=a-'L'; a2[i]=b-'L'; g[a1[i]][a2[i]]=g[a2[i]][a1[i]]=1; } memset(ok,0,sizeof ok); bool fail; for(int s=0;s<all;s++) { fail=0; for(int i=0;i<15&&!fail;i++)if(s&(1<<i)) for(int j=i+1;j<15&&!fail;j++)if(s&(1<<j)) if(g[i][j]) fail=1; ok[s]=fail?0:1; } memset(f,0x3f,sizeof f); f[0]=0; for(int s=1;s<all;s++) { for(int s0=s&(s-1);s0;s0=s&(s0-1)) if(ok[s^s0]) if(f[s]>f[s0]+1) { f[s]=f[s0]+1; pre[s]=s0; } if(ok[s]) if(f[s]>f[0]+1) { f[s]=f[0]+1; pre[s]=0; } } printf("%d ",f[all-1]-2); int p=f[all-1]; for(int s=all-1;s;s=pre[s]) { for(int i=0;i<15;i++) if((s^pre[s])&(1<<i)) pos[i]=p; p--; } for(int i=1;i<=n;i++) { if(pos[a1[i]]<pos[a2[i]]) printf("%c %c ",a1[i]+'L',a2[i]+'L'); else printf("%c %c ",a2[i]+'L',a1[i]+'L'); } } return 0; }