Exclusive Access 2 UVA - 1439

大致题意:给定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\n",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\n",a1[i]+'L',a2[i]+'L');
            else 
                printf("%c %c\n",a2[i]+'L',a1[i]+'L');
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/mgnfcnt/p/9263549.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值