UVA - 1439 Exclusive Access 2(转化为图论模型)

题目

这题题目比较复杂,我就简述一下,系统中有n ( 1 < = n < = 100 ) (1<=n<=100) 个进程和由L-Z大写字母表示的资源,资源不接受并发访问,每个进程同时需要两个资源,由此可以构建等待链(等待链定义见原题),问如何安排每个进程的资源获取顺序,使得最长的等待链最小

分析

这题重要的是建模,把原问题转化为图模型,每个资源变为一个点,每个进程变为一条无向边连接着所需要的资源,那么安排等待资源顺序就相当于给无向边定向,例如进程1需要资源L和M才能运行,那么就有两种可能,第一种是先获取L,再获取M,定向后就是L->M,第二种是先获取M,再获取L,定向后就是M->L
然后我们的目标就转化为了n条边如何定向,才能使图中无环且最长路最短,图中有环就说明存在死锁,就是n个人做成一个环分n只筷子(筷子在环中的空格中),每个人手中都有一只(都先拿左筷子),不愿意放开,但是都需要两只筷子才能吃饭(少右筷子),吃完饭之后才能放下筷子,把筷子给别人用,这就是死锁

接下来将节点分层,分为p层,同层的节点之间无边相连,对于任意一条边,把它定向为层数小的节点指向层数大的节点,那么定向后图中肯定没有圈,而且最长路长度小于p,按照紫书上的解释,最长路长度正好等于p-1,所以求最小分层数量即可求解,最小分层数量等于图的点涂色的最少颜色数量

注意 这道题中判断点的子集是否是独立集这一步要预处理,这一步时间复杂度就会变为 O ( E 2 V ) O(|E|*2^|V|) ,否则在DP函数中调用判断是否是独立集的函数,这一步时间复杂度是 O ( E 3 V ) O(|E|*3^|V|) ,因为判断点涂色是 O ( 3 V ) O(3^|V|) ,所以需要预处理,不然会超时

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <vector>
#include <utility>
using namespace std;
const int maxn=(1<<15),maxe=105,Inf=1000000000;
int n,u,v,S,d[maxn],son[maxn],independent[maxn],color[20];
char r1,r2;
pair<int,int> nodePair[maxe];
vector<int> edge;

bool edgeInside(int t){
    for(int i=0;i<n;++i){
        if((t|edge[i])==t) return true;
    }
    return false;
}

int DP(int nodes){
    int &t=d[nodes];
    if(t>=0) return t;
    t=Inf;
    for(int s=nodes;s;s=(s-1)&nodes){
        if(independent[s]){
            int temp=DP(nodes^s)+1;
            if(temp<t){
                t=temp;
                son[nodes]=s;  //记录最优的解
            }
        }
    }
    return t;
}

int main(void){
    //n代表进程数(边数),m代表资源数(节点数)
    while(cin>>n){
        edge.clear();
        S=0;
        for(int i=0;i<n;++i){
            scanf(" %c %c",&r1,&r2);
            u=r1-'L';
            v=r2-'L';
            nodePair[i]=make_pair(u,v);
            edge.push_back((1<<u)|(1<<v));
            S|=(1<<u);
            S|=(1<<v);
        }
        //枚举S的子集s
        memset(d,-1,sizeof(d));
        memset(son,-1,sizeof(son));
//        memset(color,-1,sizeof(color));
        memset(independent,0,sizeof(independent));
        for(int s=S;s;s=(s-1)&S){  //对判断s是否是独立集的预处理,节省时间
            independent[s]=(!edgeInside(s));
        }
        d[0]=0;
        DP(S);
        printf("%d\n",d[S]-2);   //一开始就是两个颜色,所以要减去
        for(int s=S,k=0;s;s=(s^son[s]),++k){
            for(int i=0;i<15;++i){
                if((son[s])&(1<<i)){
                    color[i]=k;
                }
            }
        }
        for(int i=0;i<n;++i){
            pair<int,int> &tpair=nodePair[i];
            if(color[tpair.first]<color[tpair.second]){
                printf("%c %c\n",tpair.first+'L',tpair.second+'L');
            }else{
                printf("%c %c\n",tpair.second+'L',tpair.first+'L');
            }
        }
    }
    return 0;
}
发布了15 篇原创文章 · 获赞 0 · 访问量 166

猜你喜欢

转载自blog.csdn.net/zpf1998/article/details/104025921
今日推荐