尋找 struct ini 隊列 開始時間 += min pri img

題目大意:

給定n,m,K,W

表示n個小時 m場電影(分為類型A、B)

K個人 若某個人連續看了兩場相同類型的電影則失去W 電影時間不能重疊

接下來給定m場電影的 s t w op

表示電影的 開始時間s 結束時間t 看完這場電影則獲得w 電影類型是op(0為A 1為B)

將一場電影拆成兩個點 s t,兩點間連線花費為-w容量為1

源點與所有電影的s點連線 花費為0容量為1

所有電影的t點與匯點連線 花費為0容量為1

若兩場電影的時間不沖突 那麽按時間順序在之間連邊

若類型相同 花費為W容量為1 否則 花費為0容量為1

最後設超級源點與源點連邊 花費為0容量為K 表示最多K個人

此時求出的 最小花費最大流 的最小花費 就是 最後最少的失去

最少的失去 就是 最大的獲得的相反數

技術分享圖片
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define INF 0x3f3f3f3f
#define mem(i,j) memset(i,j,sizeof(i))
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
const int N=405;
const int mod=1e9+7;

int n,m;
struct NODE { int s,t,w,op; }node[205];
struct Edge
{
    int from,to,cap,flow,cost;
    Edge(int u,int v,int ca,int f,int co):from(u),to(v),cap(ca),flow(f),cost(co){};
};

struct MCMF
{
    int n,m,s,t;
    vector<Edge> edges;
    vector<int> G[N];
    int inq[N];//是否在隊列中
    int d[N];//距離
    int p[N];//上一條弧
    int v[N];//可改進量

    void init(int n) //初始化 頂點為 0~n-1
    {
        this->n=n;
        for(int i=0;i<=n;i++) G[i].clear();
        edges.clear();
    }

    void AddEdge(int from,int to,int cap,int cost)//加邊
    {
        edges.push_back(Edge(from,to,cap,0,cost));
        edges.push_back(Edge(to,from,0,0,-cost));
        int m=edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }

    bool SPFA(int s,int t,int &flow,int &cost)//尋找最小費用的增廣路,使用引用同時修改原flow,cost
    {
        for(int i=0;i<n;i++) d[i]=INF;
        memset(inq,0,sizeof(inq));
        d[s]=0;inq[s]=1;p[s]=0;v[s]=INF;
        queue<int>Q; Q.push(s);
        while(!Q.empty()) {
            int u=Q.front(); Q.pop();
            inq[u]--;  
            for(int i=0;i<G[u].size();i++) {
                Edge& e=edges[G[u][i]];
                if(e.cap>e.flow && d[e.to]>d[u]+e.cost) {//滿足可增廣且可變短
                    d[e.to]=d[u]+e.cost;
                    p[e.to]=G[u][i];
                    v[e.to]=min(v[u],e.cap-e.flow);
                    if(!inq[e.to]) inq[e.to]++,Q.push(e.to);
                }
            }
        } 
        if(d[t]==INF) return false;//匯點不可達則退出
        flow+=v[t];
        cost+=d[t]*v[t];
        int u=t;
        while(u!=s) {//更新正向邊和反向邊 
            edges[p[u]].flow+=v[t];
            edges[p[u]^1].flow-=v[t];
            u=edges[p[u]].from;
        }
        return true;
    }

    int MincotMaxflow(int s,int t)
    {
        int flow=0,cost=0;
        while(SPFA(s,t,flow,cost));
        return cost;
    }
}MM;

int main()
{
    int _; scanf("%d",&_);
    while(_--) {
        int n,m,K,W;
        scanf("%d%d%d%d",&n,&m,&K,&W);
        MM.init(2*m+3);
        inc(i,1,m) {
            int s,t,w,op;
            scanf("%d%d%d%d",&s,&t,&w,&op);
            node[i]={s,t,w,op};
            MM.AddEdge(i*2,i*2+1,1,-w);
            MM.AddEdge(1,i*2,1,0);
            MM.AddEdge(i*2+1,m*2+2,1,0);
        }
        inc(i,1,m) inc(j,i+1,m) {
            if(node[i].t<=node[j].s) {
                if(node[i].op==node[j].op)
                    MM.AddEdge(i*2+1,j*2,1,W);
                else MM.AddEdge(i*2+1,j*2,1,0);
            }
            if(node[j].t<=node[i].s) {
                if(node[i].op==node[j].op)
                    MM.AddEdge(j*2+1,i*2,1,W);
                else MM.AddEdge(j*2+1,i*2,1,0);
            }
        }
        MM.AddEdge(0,1,K,0);
        int ans=MM.MincotMaxflow(0,m*2+2);
        printf("%d\n",-ans);
    }

    return 0;
}
View Code

hdu 6437 /// 最小費用最大流 負花費 SPFA模板