bzoj1449/2895[JSOI2009]球队收益

版权声明:本文为一名蒟蒻的原创文章,大神转载的话顺便说个出处呗。 https://blog.csdn.net/cgh_Andy/article/details/51895510

真是道挺不错的题,构图很棒。 而且还是个双倍经验题23333,由截图可见,权限狗的题数据更好、

我觉得HZWER大神和硕神都讲得很好了,我也就继续偷懒了安静硕神的 hzwer's

分析可以参考硕神的,关于构图,我们要想清楚怎么拆边,细节不太多,挺好的题。

贴代码

#include
#include
#include
#include
#include
#include
#define Max 0x7fffffff
#define me(a,x) memset(a,x,sizeof a)
using namespace std;
struct node
{
    int x,y,c,d,next;
}a[50100]; int len,first[6010];
void ins(int x,int y,int c,int d)
{
    a[++len].x=x,a[len].y=y,a[len].c=c,a[len].d=d;
    a[len].next=first[x],first[x]=len;
    a[++len].x=y,a[len].y=x,a[len].c=0,a[len].d=-d;
    a[len].next=first[y],first[y]=len;
}
int d[6010],t,l[6010];
bool v[6010];
queueq;
bool spfa()
{
    for(int i=0;i<=t;i++)l[i]=v[i]=0,d[i]=Max;
    v[0]=1,d[0]=0; q.push(0);
    while(!q.empty())
    {
        int x=q.front();
        for(int k=first[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(d[y]>d[x]+a[k].d && a[k].c)
            {
                d[y]=d[x]+a[k].d;
                l[y]=k;
                if(!v[y]){v[y]=1; q.push(y);}
            }
        }
        q.pop(); v[x]=0;
    }
    return d[t]!=Max;
}
int win[5010],lose[5010],c1[5010],c2[5010];
int in[5010];
int main()
{
    int n,m,i,j,x,y;
    scanf("%d%d",&n,&m); t=n+m+1;
    for(i=1;i<=n;i++)scanf("%d%d%d%d",&win[i],&lose[i],&c1[i],&c2[i]);
    int ans=0; me(in,0);
    len=1; me(first,0);
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        in[x]++,in[y]++,lose[x]++,lose[y]++;
        ins(i,x+m,1,0),ins(i,y+m,1,0);
        ins(0,i,1,0);
    }
    for(i=1;i<=n;i++)
        ans+=c1[i]*win[i]*win[i]+c2[i]*lose[i]*lose[i];
    for(i=1;i<=n;i++)
       for(j=1;j<=in[i];j++)
       {
           ins(i+m,t,1,c1[i]*(2*win[i]+1)+c2[i]*(-2*lose[i]+1));
           win[i]++,lose[i]--;
       }
    while(spfa())
    {
        for(i=l[t];i;i=l[a[i].x])
          a[i].c--,a[i^1].c++;
        ans+=d[t];
    }
    printf("%d\n",ans);
    return 0;
}

展开阅读全文

没有更多推荐了,返回首页