【刷題】洛谷 P3872 [TJOI2010]電影迷
題目描述
小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]電影迷