2018年2月8日训练日记

明明思路对了,却是TLE。。。(经过改正变成了RE)

无奈之下,又去翻了饶齐大佬的博客,具体内容如下:

HDU 1853 Cyclic Tour(最小费用流)
题意:
给你一个N个点M条边的带权有向图,现在要你求这样一个值:
该有向图中的所有顶点正好被1个或多个不相交的有向环覆盖(每个节点只能被一个有向环包含).
这个值就是 所有这些有向环的权值和. 要求该值越小越好.

分析:

下面用费用流再做一次,由于图中的每个顶点最多只能经过一次,那么我们自然想到了把每个点i分成i和i+n两个点. 具体建图如下:
源点s编号0, 所有节点编号1-n和n+1-2*n, 汇点t编号2*n+1.
源点s到第i个点有边 ( s, i, 1, 0)
如果从i点到j点有权值为w的边,那么有边 (i, j+n, 1, w)

每个节点到汇点有边 (i+n, t, 1, 0)

最终如果最大流==n的话,那么最小费用就是我们所求. 否则输-1.

其实任意类似的有向环最小权值覆盖问题都可以用本方法解或用KM算法解.下面说下为什么本建图方法是正确的:

其实就是我们到底要选哪n条不同的边的问题,如果最大流==n的话,我们可以得到4个结论:

1.    我们通过最大流选取了n条不同的(从左边点集到右边点集的类似于(i, j+n)的这种)边

2.    这n条边的起点正好覆盖了n个不同的顶点

3.    这n条边的终点正好覆盖了n个不同的顶点

4.    每个顶点必然是一条边的终点且是另外一条边的起点

最终我们通过最小费用最大流选的这n条边必然组成了1个(或多个)不相交的有向环且费用最小(必要条件,新问题有解->原问题有解)(如果还存在费用更小的有向环,那么我们的算法肯定会找到(充分条件,即原问题有解->新问题有解).

另外,还有一道题就是HDU 4406 GPA 

就是临近考试,你要复习来提高成绩,你有m门课,n天复习,每天只能复习一门课,每门课一天最多复习k次,复习完一次成绩就会加1分,每天只能复习一部分课程。给你每门课的学分以及基础分和每门课的绩点计算公式,GPA的计算公式,求你经过复习后最高能够获得的GPA是多少。如果最终有某一门不够60分,GPA为0,分最高为100分。

想了半天,还是能够想到思路的。建立源点s和汇点t,每一天都建立一条到t的边,容量为k,费用为0,每门课向能复习的那天连容量为k费用为0的边。那么问题的关键就来了:

因为要先保证每门分够60分,所以基础分不够60分的科目,连一条s到这门课的边,容量为60-s,费用为INF,然后添加s到这门课的40条边(因为满分为100,而且每增加一分增加的绩点是不同的),假设分数为p,学分为w,那么这40条边的容量就是1,费用为(f(p+1,w)-f(p,w)),其中f(p,w)=(4.0-3.0*(100-x)*(100-x)/1600)*w;对于基础分够60分的科目,假设基础分为x,那么就做100-x条s到这门课的边,容量为1,费用为(f(p+1,w)-f(p,w))。最后求最大费用最大流,统计s引出的边的流量加上基础分的总分数,还有小于60分的就输出0,否则就算出GPA。。。

前一天:我感觉我的思路对了呀,为啥代码样例都过不了???sad。。。明天找找错。。。应该是细节出了问题吧。。。

今天:原来是有个地方+-号写错了。。改过来秒A。。。

AC code:

#pragma comment(linker,"/STACK:102400000,102400000")
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=1005;
const int INF=1e9+7;
struct edge{
 int from,to,cap,flow;
 double cost;
 edge(){}
 edge(int f,int t,int c,int fl,double co):from(f),to(t),cap(c),flow(fl),cost(co){}
};
struct MCMF
{
    int n,m,s,t;
    vector edges;
    vector G[maxn];
    bool inq[maxn];
    double d[maxn];
    int p[maxn],a[maxn];
    void init(int n,int s,int t)
    {
        this->n=n,this->s=s,this->t=t;
        edges.clear();
        for(int i=0;iq;
     for(int i=0;i<=t;++i)d[i]=(-1.0*INF);
     memset(inq,false,sizeof(inq));
     memset(p,-1,sizeof(p));
     memset(a,0,sizeof(a));
     q.push(s),inq[s]=true;
     d[s]=0,a[s]=INF;
     while(!q.empty())
     {
         int u=q.front();q.pop();
         inq[u]=false;
         for(int i=0;ie.flow&&d[e.to]


短暂而又快乐的寒假集训就要结束了。。。然而还是要继续努力。。。


你可能感兴趣的:(训练日记,图论,网络流)