1. 程式人生 > >【刷題】洛谷 P3872 [TJOI2010]電影迷

【刷題】洛谷 P3872 [TJOI2010]電影迷

得到 看電影 不同 res putc 相反數 urn oid pop

題目描述

小A是一個電影迷,他收集了上百部的電影,打算從中挑出若幹部在假期看完。他根據自己的口味和網上的介紹,對每部電影X都打了一個分數vX,表示自己喜歡的程度。這個分數的範圍在-1000至1000之間,越大表示越喜歡。小A每看一部電影X,他的體驗值就會加上vX。

另外,因為某些電影是組成一個系列的,比如著名的《終結者》系列、《黑客帝國》系列等等,如果小A只看了前一部而沒有看後一部的話,他就會覺得不是很爽。準確來講,對於任意兩部不同的電影X,Y,他們可能存在一個依賴值dXY,表示如果小A看了X但是沒看Y,他的體驗值就會減少dXY。(註意與觀看的順序無關,只要兩部都看過,就不會減少體驗值)

現在他要選出若幹電影來看,使得得到的總的體驗值最大。如果他無法得到正的體驗值,就輸出0。

輸入輸出格式

輸入格式:

輸入的第一行是兩個整數:電影總數N和依賴關系數目M。第二行包含用空格隔開的N個數,表示對每部電影的打分。接下來M行,每行包含三個整數X, Y, dXY,表示一個依賴關系。每個有序對(X,Y)最多出現一次。(1 ≤ X,Y ≤ N)

輸出格式:

輸出一個整數,表示小A能得到的最大體驗值。

輸入輸出樣例

輸入樣例#1:

2 2
100 -50
1 2 49
2 1 10

輸出樣例#1:

51

說明

如果小A只看電影1,體驗值為100-49 = 51。如果只看電影2,體驗值為-50-10 = -60。如果兩部都看,體驗值為100+(-50) = 50。所以應該只看電影1。

數據規模與約定

對於20%的數據,1 ≤ N ≤ 15

對於100%的數據,1 ≤ N ≤ 100, -1000 ≤ vX ≤ 1000, 0 < dXY ≤ 1000

每個測試點時限1秒

題解

最大權閉合子圖模板題
先強行看所有正權值的電影,即源點向所有正權值的點連邊,邊權為點的權值
強制不看負權值的電影,即所有負權值的點向匯點連邊,邊權為點的權值的相反數
中間的限制關系,兩兩連邊,權值就為減少的值的絕對值
那麽考慮割開整個圖,與源點相連的就是要看的,與匯點相連的就是不看的
那麽割的代價就是所有正權值的和需要減少的
我們要最後的答案最大,於是割要最小
跑最小割,用正權值的和減去代價即為答案

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=100+10,MAXM=MAXN*MAXN+10,inf=0x3f3f3f3f;
int n,m,e=1,beg[MAXN],cur[MAXN],vis[MAXN],clk,s,t,ans,level[MAXN],to[MAXM<<1],nex[MAXM<<1],cap[MAXM<<1];
std::queue<int> q;
template<typename T> inline void read(T &x)
{
    T data=0,w=1;
    char ch=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
    if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void insert(int x,int y,int z)
{
    to[++e]=y;
    nex[e]=beg[x];
    beg[x]=e;
    cap[e]=z;
    to[++e]=x;
    nex[e]=beg[y];
    beg[y]=e;
    cap[e]=0;
}
inline bool bfs()
{
    memset(level,0,sizeof(level));
    level[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(register int i=beg[x];i;i=nex[i])
            if(cap[i]&&!level[to[i]])level[to[i]]=level[x]+1,q.push(to[i]);
    }
    return level[t];
}
inline int dfs(int x,int maxflow)
{
    if(x==t||!maxflow)return maxflow;
    vis[x]=clk;
    int res=0;
    for(register int &i=cur[x];i;i=nex[i])
        if((vis[to[i]]^vis[x])&&cap[i]&&level[to[i]]==level[x]+1)
        {
            int f=dfs(to[i],min(cap[i],maxflow));
            res+=f;
            cap[i]-=f;
            cap[i^1]+=f;
            maxflow-=f;
            if(!maxflow)break;
        }
    return res;
}
inline int Dinic()
{
    int res=0;
    while(bfs())clk++,memcpy(cur,beg,sizeof(cur)),res+=dfs(s,inf);
    return res;
}
int main()
{
    read(n);read(m);
    s=n+1,t=s+1;
    for(register int i=1;i<=n;++i)
    {
        int x;read(x);
        if(x>=0)ans+=x,insert(s,i,x);
        else insert(i,t,-x);
    }
    for(register int i=1;i<=m;++i)
    {
        int u,v,k;read(u);read(v);read(k);
        insert(u,v,k);
    }
    write(ans-Dinic(),'\n');
    return 0;
}

【刷題】洛谷 P3872 [TJOI2010]電影迷