先将所有的攻击力加起来
然后用费用流跑增加的攻击力
建图:
建立成一个二分图
源点向Non-t连边,容量为1,费用为0,Non-t向Tun连边,容量为1,费用为 - max(合成能够增加的攻击力-两个材料怪的攻击力和,0),Tun向着汇点连边,容量为1,费用为0。
一开始用了拆点使得每个点只能用一次,通过费用流来决策 自身攻击力 和 合成攻击力 的选择,然后一直TLE(其实不是拆点的过)。最后其实是通过人工直接判断的,如果合成攻击力大于材料攻击力和,那费用就变成0。
// whn6325689
// Mr.Phoebe
// http://blog.csdn.net/u013007900
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
#include <functional>
#include <numeric>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define eps 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LLINF 1LL<<62
#define speed std::ios::sync_with_stdio(false);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;
typedef vector<int> vi;
#define CLR(x,y) memset(x,y,sizeof(x))
#define CPY(x,y) memcpy(x,y,sizeof(x))
#define clr(a,x,size) memset(a,x,sizeof(a[0])*(size))
#define cpy(a,x,size) memcpy(a,x,sizeof(a[0])*(size))
#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define lowbit(x) (x&(-x))
#define MID(x,y) (x+((y-x)>>1))
#define ls (idx<<1)
#define rs (idx<<1|1)
#define lson ls,l,mid
#define rson rs,mid+1,r
#define root 1,1,n
template<class T>
inline bool read(T &n)
{
T x = 0, tmp = 1;
char c = getchar();
while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
if(c == EOF) return false;
if(c == '-') c = getchar(), tmp = -1;
while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
n = x*tmp;
return true;
}
template <class T>
inline void write(T n)
{
if(n < 0)
{
putchar('-');
n = -n;
}
int len = 0,data[20];
while(n)
{
data[len++] = n%10;
n /= 10;
}
if(!len) data[len++] = 0;
while(len--) putchar(data[len]+48);
}
//-----------------------------------
const int N=310;
const int M=310*310;
struct Graph
{
struct Edge
{
int v,next,w,flow;
Edge(){}
Edge(int a,int b,int c,int d):next(a),v(b),w(c),flow(d){}
}E[M<<1];
int head[N],pre[N],dis[N];
int beg,end,flow,cost;
bool h[N];
int path[N];
int NE,NV;
void init(int n)
{
NE=0;NV=n;
memset(head,-1,sizeof(int)*(n+10));
}
void addedge(int u,int v,int flow,int w)
{
E[NE]=Edge(head[u],v,w,flow);
head[u]=NE++;
E[NE]=Edge(head[v],u,-w,0);
head[v]=NE++;
}
bool update(int u,int v,int w)
{
if(dis[u]+w<dis[v])
{
dis[v]=dis[u]+w;
return true;
}
return false;
}
bool spfa()
{
CLR(pre,-1);CLR(h,0);
for(int i=0;i<=NV;i++) dis[i]=INF;
dis[beg]=0;
queue<int> q;
q.push(beg);
while(!q.empty())
{
int u=q.front(),v;
q.pop();
h[u]=0;
for(int i=head[u];~i;i=E[i].next)
{
v=E[i].v;
if(E[i].flow>0 && update(u,v,E[i].w))
{
pre[v]=u;path[v]=i;
if(!h[v])
{
h[v]=1;
q.push(v);
}
}
}
}
if(pre[end]==-1) return false;
return true;
}
int mincost_maxflow(int s,int t)
{
this->beg=s;this->end=t;
flow=0,cost=0;
while(spfa())
{
int Min=INT_MAX;
for(int i=end;i!=beg;i=pre[i])
if(Min>E[path[i]].flow)
Min=E[path[i]].flow;
for(int i=end;i!=beg;i=pre[i])
{
E[path[i]].flow-=Min;
E[path[i]^1].flow+=Min;
}
flow+=Min;
cost+=dis[end];
}
return cost;
}
void print()
{
puts("GRAPH:");
for(int i=0; i<=NV; i++)
{
if(!head[i])
continue;
printf("%d ->",i);
for(int j=head[i]; ~j; j=E[j].next)
printf("%d(%d) ",E[j].v,E[j].flow);
putchar('\n');
}
}
}g;
struct OP
{
int le,at,idx;
OP(){}
OP(int a,int b,int c):le(a),at(b),idx(c){}
bool operator < (const OP &b) const
{
return le<b.le;
}
}tt[N],nt[N];
int cnt,cnn;
int ty[N],le[N];
int atk[30];
int ma[N][N];
int main()
{
freopen("data.txt","r",stdin);
int T,n,m;
read(T);
while(T--)
{
read(n),read(m);
g.init(n+2);cnt=cnn=0;CLR(ma,0);CLR(atk,0);
int sum=0;
for(int i=1,at;i<=n;i++)
{
read(ty[i]),read(le[i]),read(at);
if(ty[i]==0)
{
g.addedge(0,i,1,0);
nt[cnn++]=OP(le[i],at,i);
}
else
{
g.addedge(i,n+1,1,0);
tt[cnt++]=OP(le[i],at,i);
}
sum+=at;
}
for(int i=1,lev,at,r,u,v;i<=m;i++)
{
read(lev),read(at),read(r);
if(r==0)
{
atk[lev]=max(atk[lev],at);
}
else if(r==1)
{
read(u);
if(ty[u]==0)
{
for(int i=0;i<cnt;i++)
if(le[u]+tt[i].le==lev)
{
ma[u][tt[i].idx]=max(ma[u][tt[i].idx],at);
}
}
else
{
for(int i=0;i<cnn;i++)
if(le[u]+nt[i].le==lev)
{
ma[nt[i].idx][u]=max(ma[nt[i].idx][u],at);
}
}
}
else
{
read(u),read(v);
if(ty[u]==0)
ma[u][v]=max(ma[u][v],at);
else
ma[v][u]=max(ma[v][u],at);
}
}
for(int i=0;i<cnn;i++)
for(int j=0;j<cnt;j++)
{
ma[nt[i].idx][tt[j].idx]=max(ma[nt[i].idx][tt[j].idx],atk[nt[i].le+tt[j].le]);
if(ma[nt[i].idx][tt[j].idx])
{
g.addedge(nt[i].idx,tt[j].idx,1,-max(ma[nt[i].idx][tt[j].idx]-nt[i].at-tt[j].at,0));
}
}
//g.print();
int ans=g.mincost_maxflow(0,n+1);
printf("%d\n",sum-ans);
}
return 0;
}
谁说拆点不能过,其实主要的复杂度在于费用流,费用流主要的复杂度在于中间那段决策是否合成部分,只要两个材料合成的怪,攻击力小于两个材料的攻击力和,就不加边。导致中间的边数目一下子减少很多,也就不怕TLE了。
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 805
typedef long long LL;
const LL INF = 1000000007;
struct edge{
int to,next,cost,cap;
}E[2000000];
struct node{
int lev,tun,atk;
}A[MAXN];
int head[MAXN],si,prevv[MAXN],preve[MAXN],que[200000],n,m,used[MAXN],C[400][400];
LL dist[MAXN];
void add_edge(int u,int v,int c,int cap)
{
//printf("%d->%d(cap:%d,cost:%d)\n",u,v,cap,c);
E[si].to=v;
E[si].cost=c;
E[si].cap=cap;
E[si].next=head[u];
head[u]=si++;
E[si].to=u;
E[si].cost=-c;
E[si].cap=0;
E[si].next=head[v];
head[v]=si++;
}
bool SPFA(int s,int t)
{
for(int i=0;i<=2*n+1;i++)dist[i]=INF,used[i]=false;
dist[s]=0;
int h=0,tail=0;
for(que[tail++]=s,used[s]=true;h<tail;h++){
int v=que[h];used[v]=false;
for(int i=head[v];~i;i=E[i].next){
if(E[i].cap>0){
int u=E[i].to;
if(dist[u]>dist[v]+E[i].cost){
// printf("dist[%d]=%I64d___dist[%d]=%I64d___cost:%d\n",u,dist[u],v,dist[v],E[i].cost);
dist[u]=dist[v]+E[i].cost;
prevv[u]=v;
preve[u]=i;
if(!used[u]){
que[tail++]=u;
used[u]=true;
}
}
}
}
}
// printf("dist:%I64d\n",dist[t]);
if(dist[t]<0)return true;
return false;
}
int min_cost_flow(int s,int t)
{
LL ans=0;
while(SPFA(s,t)){
int d=INF;
for(int v=t;s!=v;v=prevv[v]){
d=std::min(d,E[preve[v]].cap);
}
ans+=d*dist[t];
for(int v=t;v!=s;v=prevv[v]){
E[preve[v]].cap-=d;
E[preve[v]^1].cap+=d;
}
}
return ans;
}
int main()
{
int T;scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
memset(head,-1,sizeof head);si=0;
memset(C,0,sizeof C);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&A[i].tun,&A[i].lev,&A[i].atk);
add_edge(0,i,0,1);
add_edge(i,i+n,-A[i].atk,1);
add_edge(i+n,n*2+1,0,1);
}
for(int i=1,lev,atk,r,u,v;i<=m;i++){
scanf("%d%d%d",&lev,&atk,&r);
if(r==0){
for(int j=1;j<=n;j++){
if(!A[j].tun)
for(int k=1;k<=n;k++)if(A[k].tun&&A[j].lev+A[k].lev==lev){
C[j][k]=std::min(C[j][k],-atk);
}
}
}
else if(r==1){
scanf("%d",&v);
if(A[v].tun){
for(int j=1;j<=n;j++)if(!A[j].tun&&A[j].lev+A[v].lev==lev){
// add_edge(j,v+n,-atk,1);
C[j][v]=std::min(C[j][v],-atk);
}
}
else{
for(int j=1;j<=n;j++)if(A[j].tun&&A[j].lev+A[v].lev==lev){
add_edge(v,j+n,-atk,1);
C[v][j]=std::min(C[v][j],-atk);
}
}
}
else{
scanf("%d%d",&u,&v);
if(A[u].tun)std::swap(u,v);
C[u][v]=std::min(C[u][v],-atk);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)if(C[i][j]<0&&C[i][j]<-A[i].atk-A[j].atk){
add_edge(i,j+n,C[i][j],1);
}
}
LL ans=-min_cost_flow(0,n*2+1);
printf("%I64d\n",ans);
}
return 0;
}