zoukankan      html  css  js  c++  java
  • HDU2883_kebab

    很好的题目。

    有不多于200个任务,每个任务要在si到ei这个时间段内完成,每个任务的任务量是ti*ni,只有一台机器,且其单位时间内可完成的任务量为m。

    现在问你,能否使所有的任务全部在规定的时间段内完成。

    首先把所有的时间都提取出来,排序,得到2*n-1个时间区间。

    网络流建模。首先创建一个超级源点和超级汇点。源点连接n个任务,与每个任务的边的容量为ni*ti,汇点连接2*n-1个时间区间,容量为时间长度与m的乘积。同时在任务和时间区间之间也需要连边,如果某个任务的时间和时间区间有公共时间段,那么他们之间连一条边,边容量为公共时间长度乘以m。这样我们只需要求整个网络的最大流,看看是否与总的工作量相等即可。

    很有意思。嘿嘿

    召唤代码君:

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <algorithm>
    #include <vector>
    #define maxn 777
    #define Inf ~0U>>1
    using namespace std;
    
    int c[maxn][maxn],d[maxn],can[maxn];
    int n,m,s,t,tot,ans;
    int ni[maxn],ti[maxn],si[maxn],ei[maxn];
    int T[maxn],N;
    vector<int> v[maxn];
    
    void _init()
    {
    	s=1,t=1+3*n,N=0,ans=tot=0;
    	for (int i=1; i<=1+3*n; i++)
    	{
    		v[i].clear();
    		for (int j=1; j<=1+3*n; j++) c[i][j]=0;
    	}
    }
    
    void graph_build()
    {
    	int L,R;
    	sort(T+1,T+1+2*n);
    	for (int i=1; i<=n; i++)
    	{
    		c[1][i+1]=ni[i]*ti[i];
    		v[1].push_back(i+1),v[i+1].push_back(1);
    	}
    	for (int i=1; i<2*n; i++)
    	{
    		c[n+1+i][3*n+1]=(T[i+1]-T[i])*m;
    		v[n+1+i].push_back(3*n+1),v[3*n+1].push_back(n+1+i);
    	}
    	for (int i=1; i<=n; i++)
    		for (int j=1; j<2*n; j++)
    		{
    			L=max(si[i],T[j]);
    			R=min(ei[i],T[j+1]);
    			if (L>=R) continue;
    			c[1+i][n+1+j]=(R-L)*m;
    			v[1+i].push_back(n+1+j),v[n+1+j].push_back(1+i);
    		}
    }
    
    void bfs()
    {
    	for (int i=s; i<=t; i++) d[i]=999999,can[i]=0;
    	queue<int> Q;
    	Q.push(t);
    	d[t]=0;
    	while (!Q.empty())
    	{
    		int cur=Q.front();
    		Q.pop();
    		for (unsigned i=0; i<v[cur].size(); i++)
    		{
    			if (c[v[cur][i]][cur]<=0) continue;
    			if (d[cur]+1<d[v[cur][i]])
    			{
    				d[v[cur][i]]=d[cur]+1;
    				Q.push(v[cur][i]);
    			}
    		}
    	}
    }
    
    int dfs(int cur,int num)
    {
    	if (cur==t) return num;
    	int k,tmp=num;
    	for (unsigned i=0; i<v[cur].size(); i++)
    	{
    		if (c[cur][v[cur][i]]<=0 || d[v[cur][i]]+1!=d[cur] || can[v[cur][i]]) continue;
    		k=dfs(v[cur][i],min(num,c[cur][v[cur][i]]));
    		if (k) c[cur][v[cur][i]]-=k,c[v[cur][i]][cur]+=k,num-=k;
    	}
    	if (num) can[cur]=1;
    	return tmp-num;
    }
    
    int Dinic()
    {
    	for (bfs(); d[s]<3*n+1; bfs()) ans+=dfs(1,Inf);
    	return ans;
    }
    
    int main()
    {
    	while (scanf("%d%d",&n,&m)!=EOF)
    	{
    		_init();
    		for (int i=1; i<=n; i++) 
    		{
    			scanf("%d%d%d%d",&si[i],&ni[i],&ei[i],&ti[i]);
    			tot+=ni[i]*ti[i];
    			T[++N]=si[i],T[++N]=ei[i];
    		}
    		graph_build();
    		if (Dinic()==tot) puts("Yes");
    			else puts("No");
    	}
    	return 0;
    }
    

      

    如有转载,请注明出处(http://www.cnblogs.com/lochan)
  • 相关阅读:
    DoTween插件的使用
    Unity3D协程的简单使用
    排序和双指针,减小时间复杂度
    Unity3D自定义菜单组件
    滑动窗口思路分析
    Unity3D中的序列化特性和DLL特性
    求数组的交集,以及贪心算法的使用
    随笔开始啦
    实例26 循环体的过滤器
    实例25 终止循环体
  • 原文地址:https://www.cnblogs.com/lochan/p/3821702.html
Copyright © 2011-2022 走看看