zoukankan      html  css  js  c++  java
  • hdu 1534(差分约束)

    Schedule Problem

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 1715    Accepted Submission(s): 757
    Special Judge


    Problem Description
    A project can be divided into several parts. Each part should be completed continuously. This means if a part should take 3 days, we should use a continuous 3 days do complete it. There are four types of constrains among these parts which are FAS, FAF, SAF and SAS. A constrain between parts is FAS if the first one should finish after the second one started. FAF is finish after finish. SAF is start after finish, and SAS is start after start. Assume there are enough people involved in the projects, which means we can do any number of parts concurrently. You are to write a program to give a schedule of a given project, which has the shortest time.
     
    Input
    The input file consists a sequences of projects.

    Each project consists the following lines:

    the count number of parts (one line) (0 for end of input)

    times should be taken to complete these parts, each time occupies one line

    a list of FAS, FAF, SAF or SAS and two part number indicates a constrain of the two parts

    a line only contains a '#' indicates the end of a project
     
    Output
    Output should be a list of lines, each line includes a part number and the time it should start. Time should be a non-negative integer, and the start time of first part should be 0. If there is no answer for the problem, you should give a non-line output containing "impossible".

    A blank line should appear following the output for each project.

     
    Sample Input
    3 2 3 4 SAF 2 1 FAF 3 2 # 3 1 1 1 SAF 2 1 SAF 3 2 SAF 1 3 # 0
     
    Sample Output
    Case 1: 1 0 2 2 3 1 Case 2: impossible
     
    Source
     
    题意:有n个项目,每个项目有一个周期,表示完成其的时间,然后下面有一些限制,SAF a b 表示 a 的开始时间要晚于 b的结束时间,FAF,SAS,FAS类似。问每个项目最早的开始时间,依下标输出.
    题解:我们假设 a的周期是 v[a] ,开始时间是 s[a],结束时间是 e[a], b类似.
    SAF 就可以表示为 s[a] - e[b]>=0 ---->s[a] - (s[b] +v[b] )>=0 这样的话就可以列出很多个关于起点的方程,然后就设立一个超级源点,和每个起点连条长度为 0 的边,从超级源点进行 spfa,得到 low数组后依次输出即可。有环则输出 impossible,今天听说spfa只要进入 sqrt(n) 次就可以判断有没有环了,这个题还真可以。。如果有题超时的话,不妨可以试试。。不过数据强的话另当别论。
    #include <iostream>
    #include <cstdio>
    #include <string.h>
    #include <queue>
    #include <algorithm>
    #include <math.h>
    using namespace std;
    typedef long long LL;
    const int INF = 999999999;
    const int N = 1000;
    struct Edge{
        int v,w,next;
    }edge[10005];
    int head[N];
    int n,tot;
    int val[N];
    void init(){
        memset(head,-1,sizeof(head));
        tot = 0;
    }
    void addEdge(int u,int v,int w,int &k){
        edge[k].v = v,edge[k].w = w,edge[k].next = head[u],head[u] = k++;
    }
    int low[N],time[N];
    bool vis[N];
    int spfa(int s){
        for(int i=0;i<=n;i++){
            vis[i] = false;
            low[i] = -INF;
            time[i] = 0;
        }
        low[s] = 0;
        time[s]++;
        queue<int> q;
        q.push(s);
        int num = ((int)sqrt(n)+1);  ///改成根号 n 可以AC...
        while(!q.empty()){
            int u = q.front();
            q.pop();
            vis[u] = false;
            for(int k=head[u];k!=-1;k=edge[k].next){
                int v = edge[k].v,w=edge[k].w;
                if(low[v]<low[u]+w){
                    low[v] = low[u]+w;
                    if(!vis[v]){
                        vis[v] = true;
                        q.push(v);
                        if(time[v]++>num) return 0;
                    }
                }
            }
        }
        return 1;
    }
    int main(){
        int t = 1;
        while(scanf("%d",&n)!=EOF,n){
            init();
            int MAX = -1;
            for(int i=1;i<=n;i++){
                scanf("%d",&val[i]);
            }
            char str[10];
            int super = 0;
            while(scanf("%s",str)){
                if(strcmp(str,"#")==0) break;
                int a,b;
                scanf("%d%d",&a,&b);
                if(strcmp(str,"SAF")==0){
                    addEdge(b,a,val[b],tot);
                }else if(strcmp(str,"FAF")==0){
                    addEdge(b,a,-(val[a]-val[b]),tot);
                }else if(strcmp(str,"FAS")==0){
                    addEdge(b,a,-val[a],tot);
                }else{
                    addEdge(b,a,0,tot);
                }
            }
            for(int i=1;i<=n;i++){
                addEdge(super,i,0,tot);
            }
            printf("Case %d:
    ",t++);
            if(spfa(super)){
                for(int i=1;i<=n;i++){
                    printf("%d %d
    ",i,low[i]);
                }
            }else{
                printf("impossible
    ");
            }
            printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    同一个人
    11.13作业第十一次AB类
    实类化对象
    字符串数组 输入3个字符串,要求按由小到大的字母顺序输出; 输入n个学生的姓名和学号到字符串数组中,在输入一个姓名,如果班级有该生则返回其信息,否则返回本班无此人
    字符数组
    作业:例题5.7 用选择法对数组中10个整数按由小到大排序。要求使用函数的方法。
    有一个3*4的矩阵,编程求出其中最大值,以及其所在的行号和列号。
    函数重载
    冒泡数组
    裴波那契数列
  • 原文地址:https://www.cnblogs.com/liyinggang/p/5698949.html
Copyright © 2011-2022 走看看