• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
AC_Artist.zig_zag
然而我依然在补题、
博客园    首页    新随笔    联系   管理    订阅  订阅

bz3112 [Zjoi2013]防守战线

这个题挺厉害的,一道线性规划和网络流结合的经典模型。

那样例来解释吧:

Min->X1+5*X2+6*X3+3*X4+4*X5

X2+X3≥1

X1+X2+X3+X4+X5≥4

X3+X4+X5≥2

X1,X2,X3,X4,X5≥0

我们可以利用对偶原理把它转化成标准形式:

Max->Y1+4*Y2+2*Y3

Y2≤1

Y1+Y2≤5

Y1+Y2+Y3≤6

Y2+Y3≤3

Y2+Y3≤4

增加松弛变量,把标准形式变成松弛形式

Max->Z=Y1+4*Y2+2*Y3

Y2+Y4=1

Y1+Y2+Y5=5

Y1+Y2+Y3+Y6=6

Y2+Y3+Y7=3

Y2+Y3+Y8=4

 

到这里,其实我们已经可以利用单纯形来解决了。这样做速度又快,代码量也很优秀。

 

接下来我们主要来研究一下网络流

分别用下面一个式子减去上面一个式子,得到:

Max->Z=Y1+4*Y2+2*Y3

Y2+Y4=1

Y1+Y5-X4=4

Y3+Y6-Y5=1

Y7-Y1-Y6=-3

Y8-Y7=1

-Y2-Y3-Y8=-4

这样我们发现,每个变量在所有式子中正负只出现了一次,正好对应了网络流流量守恒的约束。于是对于每个式子建立一个点,那么每个变量对应一条边,从一个点流出,向另一个点流入。这样,对于等式右边的常数C,如果是正的,对应从源点向该点连一条流量C,费用0的边;如果是负的对应从该点向汇点连一条流量-C,费用0的边。对于每个变量,从它系数为正的式子向系数为负的式子连一条容量为+oo,费用为它在目标函数里系数的边。这样我们的网络流模型就构造完毕了。

用spfa暴力增广可以得到70分(后面的点会超时),如果用更快一点的原始对偶或者zkw是可以得到满分的。这里只说说zkw。由于本人技艺不精,一开始不知道zkw对于这种有负边的图需要特殊处理,所以一直没搞出来,后来经过高人指点,知道这种情况需要跑一边spfa初始化距离标号。在这个题中由于是最大费用流,那么距离标号的意义就是到汇点的最大距离,于是从汇点开始沿着反向边跑一次最短路就可以了。

献上代码:

单纯形

defend
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstring>
 6 #define maxn 1010
 7 #define maxm 10010
 8 #define inf 2147483647
 9 using namespace std;
10 int a[maxn][maxm],next[maxm];
11 int n,m;
12 
13 void pivot(int l,int e)
14 {
15     int last=-1;
16     for (int i=0;i<=m;i++)
17         if (a[l][i])
18         {
19             next[i]=last;
20             last=i;
21         }
22     for (int i=0;i<=n;i++)
23     {
24         if (a[i][e]==0||i==l) continue;
25         for (int j=last;j!=-1;j=next[j])
26         {
27             //cout<<j<<' ';
28             if (j==e) continue;
29             a[i][j]-=a[i][e]*a[l][j];
30         }
31         //cout<<endl;
32         a[i][e]=-a[i][e];
33     }
34 }
35 
36 int simplex()
37 {
38     while (1)
39     {
40         int now=0;
41         for (int i=1;i<=m;i++) 
42             if (a[0][i]>0) { now=i; break; }
43         if (now==0) return -a[0][0];
44         int tmp,mi=inf;
45         for (int i=1;i<=n;i++)
46         {
47             if (a[i][now]>0&&a[i][0]<mi)
48             {
49                 tmp=i;
50                 mi=a[i][0];
51             }
52         }
53         pivot(tmp,now);
54     }
55 }
56 
57 int main()
58 {
59     //freopen("defend.in","r",stdin);
60     scanf("%d%d",&n,&m);
61     for (int i=1;i<=n;i++) scanf("%d",&a[i][0]);
62     int x,y;
63     for (int i=1;i<=m;i++)
64     {
65         scanf("%d%d%d",&x,&y,&a[0][i]);
66         for (int j=x;j<=y;j++)
67             a[j][i]=1;
68     }
69     int ans=simplex();
70     printf("%d\n",ans);
71     return 0;
72 }

 

zkw

defend
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cmath>
  5 #include<cstring>
  6 #define maxn 1010
  7 #define maxm 200000
  8 #define inf 2147483647
  9 using namespace std;
 10 struct et
 11 {
 12     int s,t,val,cost,next;
 13 }e[maxm];
 14 int fir[maxn],a[maxn],dis[maxn],v[maxn],q[maxm],pre[maxn];
 15 bool inque[maxn];
 16 int n,m,st,ed,tot,ans;
 17 
 18 void prepare()
 19 {
 20     for (int i=st;i<=ed;i++) dis[i]=-inf;
 21     int head=0,tail=1;
 22     q[1]=ed; dis[ed]=0; inque[ed]=1;
 23     while (head<tail)
 24     {
 25         int now=q[++head];
 26         for (int j=fir[now];j;j=e[j].next)
 27         {
 28             int k=e[j].t;
 29             if (e[j^1].val&&dis[k]<dis[now]+e[j^1].cost)
 30             {
 31                 dis[k]=dis[now]+e[j^1].cost;
 32                 if (!inque[k]) q[++tail]=k,inque[k]=1;
 33             }
 34         }
 35         inque[now]=0;
 36     }
 37 }
 38 
 39 int dfs(int now,int flow)
 40 {
 41     if (now==ed)
 42     {
 43         ans+=dis[st]*flow;
 44         return flow;
 45     }
 46     int sap=0;    v[now]=1;
 47     for (int j=fir[now];j;j=e[j].next)
 48     {
 49         int k=e[j].t;
 50         if (!v[k]&&e[j].val&&dis[now]==dis[k]+e[j].cost)
 51         {
 52             int tmp=dfs(k,min(e[j].val,flow-sap));
 53             e[j].val-=tmp;
 54             e[j^1].val+=tmp;
 55             sap+=tmp;
 56             if (sap==flow) return sap;
 57         }
 58     }
 59     return sap;
 60 }
 61 
 62 bool adjust()
 63 {
 64     int tmp=-inf;
 65     for (int i=st;i<=ed;i++) if (v[i])
 66         for (int j=fir[i];j;j=e[j].next)
 67         {
 68             int k=e[j].t;
 69             if (!v[k]&&e[j].val) tmp=max(tmp,dis[k]+e[j].cost-dis[i]);
 70         }
 71     if (tmp==-inf) return 0;
 72     for (int i=st;i<=ed;i++) if (v[i])
 73         dis[i]+=tmp;
 74     return 1;
 75 }
 76 
 77 void add(int x,int y,int z,int w)
 78 {
 79     e[++tot].s=x; e[tot].t=y; e[tot].val=z; e[tot].cost=w; e[tot].next=fir[x]; fir[x]=tot;
 80     e[++tot].s=y; e[tot].t=x; e[tot].val=0; e[tot].cost=-w; e[tot].next=fir[y]; fir[y]=tot;
 81 }
 82 
 83 int main()
 84 {
 85     //freopen("defend.in","r",stdin);
 86     scanf("%d%d",&n,&m);
 87     st=0; ed=n+2; tot=1;
 88     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
 89     for (int i=1;i<=n+1;i++)
 90         if (a[i]-a[i-1]>0) add(st,i,a[i]-a[i-1],0);
 91         else add(i,ed,a[i-1]-a[i],0);
 92     int x,y,z;
 93     for (int i=1;i<=m;i++)
 94     {
 95         scanf("%d%d%d",&x,&y,&z);
 96         add(x,y+1,inf,z);
 97     }
 98     for (int i=1;i<=n;i++)
 99         add(i,i+1,inf,0);
100     prepare();
101     //for (int i=st;i<=ed;i++) cout<<dis[i]<<' '; cout<<endl;
102     do 
103         do memset(v,0,sizeof(v));
104         while (dfs(st,inf));
105     while (adjust());
106     printf("%d\n",ans);
107     return 0;
108 }

 

 

 

AC without art, no better than WA !
posted @ 2013-04-23 08:38  Zig_zag  阅读(1612)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3