HDU 5383 Yu-Gi-Oh!

先将所有的攻击力加起来
然后用费用流跑增加的攻击力
建图:
建立成一个二分图
源点向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;
}

你可能感兴趣的:(HDU 5383 Yu-Gi-Oh!)