hdoj 3572 Task Schedule【建立超级源点超级汇点】

Task Schedule

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6000    Accepted Submission(s): 1922


Problem Description
Our geometry princess XMM has stoped her study in computational geometry to concentrate on her newly opened factory. Her factory has introduced M new machines in order to process the coming N tasks. For the i-th task, the factory has to start processing it at or after day Si, process it for Pi days, and finish the task before or at day Ei. A machine can only work on one task at a time, and each task can be processed by at most one machine at a time. However, a task can be interrupted and processed on different machines on different days.
Now she wonders whether he has a feasible schedule to finish all the tasks in time. She turns to you for help.
 

 

Input
On the first line comes an integer T(T<=20), indicating the number of test cases.

You are given two integer N(N<=500) and M(M<=200) on the first line of each test case. Then on each of next N lines are three integers Pi, Si and Ei (1<=Pi, Si, Ei<=500), which have the meaning described in the description. It is guaranteed that in a feasible schedule every task that can be finished will be done before or at its end day.
 

 

Output
For each test case, print “Case x: ” first, where x is the case number. If there exists a feasible schedule to finish all the tasks, print “Yes”, otherwise print “No”.

Print a blank line after each test case.
 

 

Sample Input
2
4 3
1 3 5
1 1 4
2 3 7
3 5 9
2 2
2 1 3
1 2 2
 

 

Sample Output
Case 1: Yes
Case 2: Yes
 
题意:有n个任务,m个机器,给你完成第i件任务的时间以及必须完成这件任务的时间区间(si,ei),一台机器一次只能执行一个任务,让你判断是否完成所有的任务;
 
题解:难在建图   注意: 我们是将天数看做流量
1、将每个任务i看做一个节点连接超级源点 s,容量为每个人物所需要的时间
2、将每个任务i看做节点, 连接完成这个任务所要进行的时间阶段内的所有点,容量为1  (表示这件任务的流量只能为1(即天数为1))
3、将所有时间段内的点连接到超级汇点t容量为m   (表示一天内共有m台机器可以同时工作)
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include<stdio.h>
#include<string.h>
#include<queue>
#include<stack>
#include<algorithm>
#define INF 0x7fffff
#define MAX 11000
#define MAXM 1001000
using namespace std;
struct node
{
    int from,to,cap,flow,next;
}edge[MAXM];
int ans,head[MAX];
int cur[MAX];
int vis[MAX];
int dis[MAX];
int sum,n,m;
int sec;//超级汇点
void init()
{
    ans=0;
    memset(head,-1,sizeof(head));
}
void add(int u,int v,int w)
{
    node E1={u,v,w,0,head[u]};
    edge[ans]=E1;
    head[u]=ans++;
    node E2={v,u,0,0,head[v]};
    edge[ans]=E2;
    head[v]=ans++;
}
void getmap()
{
    int i,j,last=-1;
    sum=sec=0;
    int bt,et,time;
    for(i=1;i<=n;i++)
    {
        scanf("%d%d%d",&time,&bt,&et);
        sum+=time;
        add(0,i,time);//超级源点连接第i件任务
        for(j=bt;j<=et;j++)
            add(i,n+j,1);//将每件任务与完成这件任务所需要的时间段内的每一天连接
        last=max(last,et);
    }
    sec=n+last+1;
    for(i=1;i<=sec;i++)
        add(n+i,sec,m);//将所有的时间段内的点指向超级汇点
}
int bfs(int beg,int end)
{
    int i;
    memset(vis,0,sizeof(vis));
    memset(dis,-1,sizeof(dis));
    queue<int>q;
    while(!q.empty())
        q.pop();
    vis[beg]=1;
    dis[beg]=0;
    q.push(beg);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(i=head[u];i!=-1;i=edge[i].next)//遍历所有的与u相连的边
        {
            node E=edge[i];
            if(!vis[E.to]&&E.cap>E.flow)//如果边未被访问且流量未满继续操作
            {
                dis[E.to]=dis[u]+1;//建立层次图
                vis[E.to]=1;//将当前点标记                                                                                                           
                if(E.to==end)//如果当前点搜索到终点则停止搜索  返回1表示有从原点到达汇点的路径
                    return 1;
                q.push(E.to);//将当前点入队
            }
        }
    }
    return 0;//返回0表示未找到从源点到汇点的路径
}
int dfs(int x,int a,int end)//把找到的这条边上的所有当前流量加上a(a是这条路径中的最小残余流量)
{
    //int i;
    if(x==end||a==0)//如果搜索到终点或者最小的残余流量为0
        return a;
    int flow=0,f;
    for(int& i=cur[x];i!=-1;i=edge[i].next)//i从上次结束时的弧开始
    {
        node& E=edge[i];
        if(dis[E.to]==dis[x]+1&&(f=dfs(E.to,min(a,E.cap-E.flow),end))>0)//如果
        {//bfs中我们已经建立过层次图,现在如果 dis[E.to]==dis[x]+1表示是我们找到的路径
        //如果dfs>0表明最小的残余流量还有,我们要一直找到最小残余流量为0
            E.flow+=f;//正向边当前流量加上最小的残余流量
            edge[i^1].flow-=f;//反向边
            flow+=f;//总流量加上f
            a-=f;//最小可增流量减去f
            if(a==0)
                break;
        }
    }
    return flow;//所有边加上最小残余流量后的值
}
int Maxflow(int beg,int end)
{
    int flow=0;
    while(bfs(beg,end))//存在最短路径
    {
        memcpy(cur,head,sizeof(head));//复制数组
        flow+=dfs(beg,INF,end);
    }
    return flow;//最大流量
}
int main()
{
    int t;
    scanf("%d",&t);
    int k=1;
    while(t--)
    {
        scanf("%d%d",&n,&m);
        init();
        getmap();
        printf("Case %d: ",k++);
        if(sum==Maxflow(0,sec))
            printf("Yes\n\n");
        else
            printf("No\n\n");
    }
    return 0;
}

  

 
posted @   非我非非我  阅读(632)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示