POJ3762 时间段用k次
生活随笔
收集整理的這篇文章主要介紹了
POJ3762 时间段用k次
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意:
? ? ? 有n個任務,每個任務有自己的開始時間和結束時間,還有完成這個任務能獲得的價值,然后每一天的同一個時刻只能執行一個任務,每個任務必須連續執行完成,最多可以工作m天,問這m天能獲得的最大價值。
思路:
? ? ? 一開始沒想太多,直接建立一個圖,然后TLE了,先說下我TLE的那個吧!,邏輯上應該沒錯,是時間過不起,我是先把每一個點差點,拆成兩個,流量1,費用是他的價值,然后虛擬出來一個點,連接所有點,流量是1,意思是所有點都可以作為這一天的開始,然后每一個點都連接干完這個活之后可以在干的另一個活,流量是1,費用0,最后所有的點在連接終點,流量1,費用0,意思是每一個點都可以作為這一天的最后一個任務,然后在超級源點那在虛擬出來一個點,和起點連接,流量m費用0,意思最多可以干m天,結果TLE了,現在說下官方題解,官方題解也非常簡單容易理解,是這樣的,我們可以吧所有涉及的時間點都拿出來,然后sort離散化一下,然后得到一個<=n*2的點集,(<是因為可能有重復的時間點),把這一串點集全都連接上,i->i+1 流量是INF,費用是0,這樣的目的是任意兩個任務之間雖然沒有交集,但是也可以用0花費連接起來,然后對于每一個任務,他的起點和終點都對應著離散化之后的某兩個點,然后把這兩個點之間倆接一條邊,流量1,費用是這個任務的價值,最后再在第一個點之前虛擬出來一個點s連接第一個點,流量是m費用是0,限制天數用的,然后在在最后一個離散化后的點連接一個虛擬的t(這個虛擬的t可以不用,我個人習慣,于是就用了),最后一遍費用流就行了。官方的這個做法的邊數是n的,我的那個是n*n的,n的這個我的都跑了1300多了,n*n的必然TLE了。
#include<map>
#include<queue>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N_node 5000
#define N_edge 50000
#define INF 1000000000
using namespace std;
typedef struct
{
? ?int from ,to ,next ,cost ,flow;
}STAR;
typedef struct
{
? ?int a ,b ,c;
}NODE;
STAR E[N_edge];
NODE node[2200];
int list[N_node] ,tot;
int mer[N_node] ,s_x[N_node] ,mark[N_node];
int num[N_node];
map<int ,int>hash;
void add(int a ,int b ,int c ,int d)
{
? ?E[++tot].from = a;
? ?E[tot].to = b;
? ?E[tot].cost = c;
? ?E[tot].flow = d;
? ?E[tot].next = list[a];
? ?list[a] = tot;
? ?
? ?E[++tot].from = b;
? ?E[tot].to = a;
? ?E[tot].cost = -c;
? ?E[tot].flow = 0;
? ?E[tot].next = list[b];
? ?list[b] = tot;
}
bool Spfa(int s ,int t ,int n)
{
? ?for(int i = 0 ;i <= n ;i ++)
? ?s_x[i] = -INF ,mark[i] = 0;
? ?queue<int>q;
? ?s_x[s] = 0 ,mark[s] = 1;
? ?q.push(s);
? ?memset(mer ,255 ,sizeof(mer));
? ?while(!q.empty())
? ?{
? ? ? int xin ,tou;
? ? ? tou = q.front();
? ? ? q.pop();
? ? ? mark[tou] = 0;
? ? ? for(int k = list[tou] ;k ;k = E[k].next)
? ? ? {
? ? ? ? ?xin = E[k].to;
? ? ? ? ?if(s_x[xin] < s_x[tou] + E[k].cost && E[k].flow)
? ? ? ? ?{
? ? ? ? ? ? s_x[xin] = s_x[tou] + E[k].cost;
? ? ? ? ? ? mer[xin] = k;
? ? ? ? ? ? if(!mark[xin])
? ? ? ? ? ? {
? ? ? ? ? ? ? ?mark[xin] = 1;
? ? ? ? ? ? ? ?q.push(xin);
? ? ? ? ? ? }
? ? ? ? ?}
? ? ? }
? ?}
? ?return mer[t] != -1;
}
int M_C_Flow(int s ,int t ,int n)
{
? ?int minflow ,maxflow = 0 ,maxcost = 0;
? ?while(Spfa(s ,t ,n))
? ?{
? ? ? minflow = INF;
? ? ? for(int i = mer[t] ;i + 1 ;i = mer[E[i].from])
? ? ? if(minflow > E[i].flow) minflow = E[i].flow;
? ? ? for(int i = mer[t] ;i + 1 ;i = mer[E[i].from])
? ? ? {
? ? ? ? ?E[i].flow -= minflow;
? ? ? ? ?E[i^1].flow += minflow;
? ? ? ? ?maxcost += minflow * E[i].cost;
? ? ? }
? ? ? maxflow += minflow;
? ?}
? ?return maxcost;
}
int main ()
{
? ?int i ,j ,n ,m;
? ?int a ,b ,c ,aa ,bb ,cc ,d;
? ?while(~scanf("%d %d" ,&n ,&m))
? ?{
? ? ? memset(list ,0 ,sizeof(list)) ,tot = 1;
? ? ? int nowid = 0;
? ? ? for(i = 1 ;i <= n ;i ++)
? ? ? {
? ? ? ? ?scanf("%d:%d:%d %d:%d:%d %d" ,&a ,&b ,&c ,&aa ,&bb ,&cc ,&d);
? ? ? ? ?node[i].a = c*1+b*60+a*3600;
? ? ? ? ?node[i].b = cc*1+bb*60+aa*3600;
? ? ? ? ?node[i].c = d;
? ? ? ? ?num[++nowid] = node[i].a;
? ? ? ? ?num[++nowid] = node[i].b;
? ? ? }
? ? ? sort(num + 1 ,num + nowid + 1);
? ? ? int now = 0;
? ? ? for(i = 1 ;i <= nowid ;i ++)
? ? ? {
? ? ? ? ?if(i == 1 || num[i] != num[i-1]) now ++;
? ? ? ? ?hash[num[i]] = now;
? ? ? }
? ? ? memset(list ,0 ,sizeof(list)) ,tot = 1;
? ? ? add(0 ,1 ,0 ,m);
? ? ? for(i = 2 ;i <= now ;i ++)
? ? ? add(i - 1 ,i ,0 ,INF);
? ? ? add(now ,now + 1 ,0 ,m);
? ? ? for(int i = 1 ;i <= n ;i ++)
? ? ? add(hash[node[i].a] ,hash[node[i].b] ,node[i].c ,1);
? ? ? int Ans = M_C_Flow(0 ,now + 1 ,now + 1);
? ? ? printf("%d\n" ,Ans);
? ?}
? ?return 0;
}
? ? ? ? ?
? ? ? ??
? ? ??
? ? ??
? ? ? ? ?
? ? ??
? ? ??
? ? ??
? ?
?
? ?
? ?
? ?
? ?
? ? ? 有n個任務,每個任務有自己的開始時間和結束時間,還有完成這個任務能獲得的價值,然后每一天的同一個時刻只能執行一個任務,每個任務必須連續執行完成,最多可以工作m天,問這m天能獲得的最大價值。
思路:
? ? ? 一開始沒想太多,直接建立一個圖,然后TLE了,先說下我TLE的那個吧!,邏輯上應該沒錯,是時間過不起,我是先把每一個點差點,拆成兩個,流量1,費用是他的價值,然后虛擬出來一個點,連接所有點,流量是1,意思是所有點都可以作為這一天的開始,然后每一個點都連接干完這個活之后可以在干的另一個活,流量是1,費用0,最后所有的點在連接終點,流量1,費用0,意思是每一個點都可以作為這一天的最后一個任務,然后在超級源點那在虛擬出來一個點,和起點連接,流量m費用0,意思最多可以干m天,結果TLE了,現在說下官方題解,官方題解也非常簡單容易理解,是這樣的,我們可以吧所有涉及的時間點都拿出來,然后sort離散化一下,然后得到一個<=n*2的點集,(<是因為可能有重復的時間點),把這一串點集全都連接上,i->i+1 流量是INF,費用是0,這樣的目的是任意兩個任務之間雖然沒有交集,但是也可以用0花費連接起來,然后對于每一個任務,他的起點和終點都對應著離散化之后的某兩個點,然后把這兩個點之間倆接一條邊,流量1,費用是這個任務的價值,最后再在第一個點之前虛擬出來一個點s連接第一個點,流量是m費用是0,限制天數用的,然后在在最后一個離散化后的點連接一個虛擬的t(這個虛擬的t可以不用,我個人習慣,于是就用了),最后一遍費用流就行了。官方的這個做法的邊數是n的,我的那個是n*n的,n的這個我的都跑了1300多了,n*n的必然TLE了。
#include<map>
#include<queue>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N_node 5000
#define N_edge 50000
#define INF 1000000000
using namespace std;
typedef struct
{
? ?int from ,to ,next ,cost ,flow;
}STAR;
typedef struct
{
? ?int a ,b ,c;
}NODE;
STAR E[N_edge];
NODE node[2200];
int list[N_node] ,tot;
int mer[N_node] ,s_x[N_node] ,mark[N_node];
int num[N_node];
map<int ,int>hash;
void add(int a ,int b ,int c ,int d)
{
? ?E[++tot].from = a;
? ?E[tot].to = b;
? ?E[tot].cost = c;
? ?E[tot].flow = d;
? ?E[tot].next = list[a];
? ?list[a] = tot;
? ?
? ?E[++tot].from = b;
? ?E[tot].to = a;
? ?E[tot].cost = -c;
? ?E[tot].flow = 0;
? ?E[tot].next = list[b];
? ?list[b] = tot;
}
bool Spfa(int s ,int t ,int n)
{
? ?for(int i = 0 ;i <= n ;i ++)
? ?s_x[i] = -INF ,mark[i] = 0;
? ?queue<int>q;
? ?s_x[s] = 0 ,mark[s] = 1;
? ?q.push(s);
? ?memset(mer ,255 ,sizeof(mer));
? ?while(!q.empty())
? ?{
? ? ? int xin ,tou;
? ? ? tou = q.front();
? ? ? q.pop();
? ? ? mark[tou] = 0;
? ? ? for(int k = list[tou] ;k ;k = E[k].next)
? ? ? {
? ? ? ? ?xin = E[k].to;
? ? ? ? ?if(s_x[xin] < s_x[tou] + E[k].cost && E[k].flow)
? ? ? ? ?{
? ? ? ? ? ? s_x[xin] = s_x[tou] + E[k].cost;
? ? ? ? ? ? mer[xin] = k;
? ? ? ? ? ? if(!mark[xin])
? ? ? ? ? ? {
? ? ? ? ? ? ? ?mark[xin] = 1;
? ? ? ? ? ? ? ?q.push(xin);
? ? ? ? ? ? }
? ? ? ? ?}
? ? ? }
? ?}
? ?return mer[t] != -1;
}
int M_C_Flow(int s ,int t ,int n)
{
? ?int minflow ,maxflow = 0 ,maxcost = 0;
? ?while(Spfa(s ,t ,n))
? ?{
? ? ? minflow = INF;
? ? ? for(int i = mer[t] ;i + 1 ;i = mer[E[i].from])
? ? ? if(minflow > E[i].flow) minflow = E[i].flow;
? ? ? for(int i = mer[t] ;i + 1 ;i = mer[E[i].from])
? ? ? {
? ? ? ? ?E[i].flow -= minflow;
? ? ? ? ?E[i^1].flow += minflow;
? ? ? ? ?maxcost += minflow * E[i].cost;
? ? ? }
? ? ? maxflow += minflow;
? ?}
? ?return maxcost;
}
int main ()
{
? ?int i ,j ,n ,m;
? ?int a ,b ,c ,aa ,bb ,cc ,d;
? ?while(~scanf("%d %d" ,&n ,&m))
? ?{
? ? ? memset(list ,0 ,sizeof(list)) ,tot = 1;
? ? ? int nowid = 0;
? ? ? for(i = 1 ;i <= n ;i ++)
? ? ? {
? ? ? ? ?scanf("%d:%d:%d %d:%d:%d %d" ,&a ,&b ,&c ,&aa ,&bb ,&cc ,&d);
? ? ? ? ?node[i].a = c*1+b*60+a*3600;
? ? ? ? ?node[i].b = cc*1+bb*60+aa*3600;
? ? ? ? ?node[i].c = d;
? ? ? ? ?num[++nowid] = node[i].a;
? ? ? ? ?num[++nowid] = node[i].b;
? ? ? }
? ? ? sort(num + 1 ,num + nowid + 1);
? ? ? int now = 0;
? ? ? for(i = 1 ;i <= nowid ;i ++)
? ? ? {
? ? ? ? ?if(i == 1 || num[i] != num[i-1]) now ++;
? ? ? ? ?hash[num[i]] = now;
? ? ? }
? ? ? memset(list ,0 ,sizeof(list)) ,tot = 1;
? ? ? add(0 ,1 ,0 ,m);
? ? ? for(i = 2 ;i <= now ;i ++)
? ? ? add(i - 1 ,i ,0 ,INF);
? ? ? add(now ,now + 1 ,0 ,m);
? ? ? for(int i = 1 ;i <= n ;i ++)
? ? ? add(hash[node[i].a] ,hash[node[i].b] ,node[i].c ,1);
? ? ? int Ans = M_C_Flow(0 ,now + 1 ,now + 1);
? ? ? printf("%d\n" ,Ans);
? ?}
? ?return 0;
}
? ? ? ? ?
? ? ? ??
? ? ??
? ? ??
? ? ? ? ?
? ? ??
? ? ??
? ? ??
? ?
?
? ?
? ?
? ?
? ?
總結
以上是生活随笔為你收集整理的POJ3762 时间段用k次的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hdu5105给你一个方程,让你求极值(
- 下一篇: UVA10125和集