【jzoj3773】小P的烦恼

题目描述
        小 P 最近遇上了大麻烦,他的高等代数挂科了。于是他只好找高代老师求情。善良的高代老师答应不挂他,但是要求小 P 帮助他一起解决一个难题。
        问题是这样的,高代老师近期要组织班上同学一起去漂流,漂流可以看做是在一张 n 个点 m 条边的有向无环图上进行的,点编号从 0 到 n-1 ,表示景点; 边是连接各景点的一定长度的河道。同时,定义编号为 s 是起点而 t 是终点。我们不妨把从 s 点到 t 点不论走什么样的路径都需要经过的边称为桥, 这些桥由于地势险要所以是危险的。现在高代老师有两条长度为 l 的安全绳,他希望用这两条安全绳覆盖尽可能长的桥,使得他们通过的桥的长度之和尽量短。

输入
        本题包含多组数据,第一行是一个数 T(T<=5)表示数据组数,对于每组数据,第一行是 5 个数,n,m,s,t,l。
        以下 m 行,每行包括三个数 si,ti,pi,表示从 si 到 ti 有一条长度为 pi 的单向边。

输出
     对于每组数据,输出一行,包括一个整数,为最优情况下通过的桥的长度之和。如果不存在从 s 到 t 的路径,请输出-1。

输入样例
1
8 9 0 7 7
0 4 1
0 1 10
1 2 9
4 2 2
2 5 8
4 3 3
5 6 6
5 6 7
6 7 5

输出样例
1

数据范围
对于 10%的数据,n<=10,m<=20
对于 30%的数据,n<=1000,m<= 10000
对于 100%的数据,n<=100000, m<=200000,0<=s,t,si,ti<n, l<=10^9,pi<=1000

思路

  emmmmmmm当时这是第三题,第一题用奇怪的方法水过了,第二题一看推不出式子,就不弄啦啦啦

  这题,一看应该能分成两步。
  1、找桥
  2、找最大覆盖方案

找桥?
  有关连通性的tarjan算法可以解决。    
  但我考场上不会。
  再一看,有向无环图,有戏,可以考虑乱搞。首先想到拓扑,桥的起点和终点至少应是拓扑序相邻的。但相邻的怎样才是桥呢?画个数轴吧。



  不是桥的那些边堆积在一起,而桥的位置只有一条边。好,我们现在需要找出相邻的,只有一条边覆盖的位置。在拓扑序上,一条边覆盖一个区间,可以用差分处理每条边就能求出覆盖数了。找桥完毕。

找最大覆盖方案?
  在当时,我没有想出来,打了的找桥也相当于是废了……
  两条绳子不好弄吧?

简化
  一条绳子怎么弄?
  再建一个数轴,从起点到终点,非桥、桥交错分布,非桥部分可以预处理最短路。
  绳子结尾位置确定了,那覆盖的长度就确定了。绳子结尾在哪?

  分情况讨论


  所以,绳子结尾在一个区间内可以等价为在一个区间的结尾。
  如何确定覆盖长度?
  用双指针可以扫出绳子能往前延伸至哪个区间,用前缀和就能求答案啦。

回归
  两条绳子怎么弄?

  如果两条绳子完全分属不同的区间,那么枚举,在一条绳子的基础上,加上这条绳子起点前一条绳子能覆盖的最大值就行了吧。
  如果后面绳子的头接着前面绳子的尾呢?



  仍等价于两倍长度的绳子!

  记f[i][j]为,以1到i号区间为结尾,j条绳子能覆盖的最大值;预处理的g[i][j]为以i号区间为结尾,长度为j的绳子能覆盖多长;pre[i]为以i号区间为结尾的绳子的起点。
  最后的方程为
  f[i][1]=min(f[i-1][1],g[i][l]);
  f[i][2]=min(f[i-1][2],f[pre[i]-1][1]+g[i][l],g[i][2l]).

找桥的其他方案
  我这个蒟蒻自己想到了这些方法,秉着分享思路的理念写了这个玩意。我在此不打算写有关tarjan的内容。
  针对有向无环图,从起点到桥的起点的方案数*桥的终点到终点的方案数=从起点到终点的总方案数。可根据此点找桥。

代码
  WA,这种傻方法,我写的这么长,就不放了吧QWQ

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <cmath>
  5 #include <algorithm>
  6 #include <cstring>
  7 #include <string>
  8 #include <queue>
  9 using namespace std;
 10 
 11 struct line
 12 {
 13     int to,next,w;
 14 }e[200050];
 15 
 16 int fl[100050],enfl[100050],inp[100050],outp[100050],hd[100050],q[100050],srt[100050],brst[100050],bren[100050],brw[100050];
 17 int t,n,m,st,en,i,j,k,x,y,z,l,tot,head,tail,cntzero,brtot,srtot,etot;
 18 int ek[400050],sumk[400050],ef[400050],sumf[400050];
 19 int dp[400050][3],pre[400050][2];
 20 
 21 void ins(int p,int s,int r)
 22 {
 23     tot++; e[tot].to=s; e[tot].next=hd[p]; e[tot].w=r; hd[p]=tot;
 24     inp[s]++; outp[p]++;
 25 }
 26 
 27 void dfs(int p)
 28 {
 29     fl[p]=1;
 30     if (p==en) return;
 31     int i1=hd[p];
 32     while (i1!=-1)
 33     {
 34         if (fl[e[i1].to]==0) dfs(e[i1].to);
 35         if (enfl[e[i1].to]==1) enfl[p]=1;
 36         if (enfl[e[i1].to]==0) {outp[p]--; inp[e[i1].to]--;}
 37         i1=e[i1].next;
 38     }
 39 }
 40 
 41 void tuopu()
 42 {
 43     brtot=0;
 44     memset(q,0,sizeof(q));
 45     memset(fl,0,sizeof(fl));
 46     memset(srt,0,sizeof(srt));
 47     head=0; tail=0; srtot=0;
 48     for (i=0;i<=n-1;i++) 
 49         if (enfl[i]==1)
 50             if (inp[i]==0) {q[tail]=i; tail++; }
 51     while (head<tail)
 52     {
 53         i=q[head]; 
 54         srtot++; srt[srtot]=i; fl[i]=srtot;
 55         j=hd[i];
 56         while (j!=-1)
 57         {
 58             if (enfl[e[j].to]==1)
 59             {
 60                 inp[e[j].to]--; outp[i]--;
 61                 if (inp[e[j].to]==0) {q[tail]=e[j].to; tail++;}
 62             }
 63             j=e[j].next;
 64         }
 65         head++;
 66     }
 67 }
 68 
 69 void findbridge()
 70 {
 71     memset(q,0,sizeof(q));
 72     memset(inp,0,sizeof(inp));
 73     for (i=0;i<=n-1;i++)
 74         if (enfl[i]==1)
 75         {
 76             j=hd[i];
 77             while (j!=-1)
 78             {
 79                 if (enfl[e[j].to]==1) 
 80                 {
 81                     q[fl[i]-1]++; q[fl[e[j].to]-1]--;
 82                 }
 83                 j=e[j].next;
 84             }
 85         }
 86 
 87     inp[0]=q[0];
 88     for (i=1;i<=srtot;i++) inp[i]=inp[i-1]+q[i];
 89 
 90     for (int i1=1;i1<=srtot;i1++)
 91     {
 92         i=srt[i1];
 93         if (enfl[i]==1)
 94         {
 95             j=hd[i];
 96             while (j!=-1)
 97             {
 98                 if (enfl[e[j].to]==1) 
 99                 {
100                     if ((fl[e[j].to]-fl[i]==1)&&(inp[fl[i]-1]==1))
101                     {
102                         brtot++; brst[brtot]=i; bren[brtot]=e[j].to; brw[brtot]=e[j].w;
103                     }
104                 }
105                 j=e[j].next;
106             }
107         }    
108     }
109 }
110 
111 int sp(int p,int r)
112 {
113     int i1,j1,k1;
114     for (i1=fl[p];i1<=fl[r];i1++) q[i1]=1<<30;
115     q[fl[p]]=0;
116     for (i1=fl[p];i1<=fl[r]-1;i1++) 
117     {
118         j1=srt[i1]; k1=hd[j1]; 
119         while (k1!=-1) 
120         {
121             if (enfl[e[k1].to]==1) q[fl[e[k1].to]]=min(q[fl[e[k1].to]],q[i1]+e[k1].w);
122             k1=e[k1].next;
123         } 
124     }
125     return q[fl[r]];
126 }
127 
128 void countt()
129 {
130     if (brtot==0) {cout<<0<<endl; return;}
131     sumk[0]=0; sumf[0]=0;
132     for (i=1;i<=brtot-1;i++) 
133     {
134         ek[2*i-1]=brw[i]; ek[2*i]=sp(bren[i],brst[i+1]); 
135         ef[2*i-1]=brw[i]; ef[2*i]=0;
136     }
137     ek[2*brtot-1]=brw[brtot]; ef[2*brtot-1]=brw[brtot];
138     for (i=1;i<=2*brtot-1;i++) {sumk[i]=ek[i]+sumk[i-1]; sumf[i]=ef[i]+sumf[i-1];}
139     int ll,rr,sum1,sum2;
140     sum1=0; ll=1; rr=1;
141     while (rr<=2*brtot-1)
142     {
143         sum1+=ek[rr]; 
144         while (sum1>l) 
145         {
146             sum1-=ek[ll]; ll++;
147         }
148         pre[rr][0]=ll;
149         rr++;
150     }
151     
152     sum1=0; ll=1; rr=1;
153     while (rr<=2*brtot-1)
154     {
155         sum1+=ek[rr]; 
156         while (sum1>2*l) 
157         {
158             sum1-=ek[ll]; ll++;
159         }
160         pre[rr][1]=ll;
161         rr++;
162     }
163     
164     dp[0][0]=0;
165     for (i=1;i<=2*brtot-1;i++)
166     {
167         sum1=sumf[i]-sumf[pre[i][0]-1];
168         sum2=sumk[i]-sumk[pre[i][0]-1];
169         if ((pre[i][0]-1)%2==1) sum1+=l-sum2;
170         dp[i][1]=sum1;
171         dp[i][0]=max(dp[i-1][0],dp[i][1]);
172     }
173     
174     dp[0][2]=0;
175     for (i=1;i<=2*brtot-1;i++)
176     {
177         sum1=sumf[i]-sumf[pre[i][1]-1];
178         sum2=sumk[i]-sumk[pre[i][1]-1];
179         if ((pre[i][1]-1)%2==1) sum1+=l-sum2;
180         dp[i][2]=max(dp[i-1][2],sum1);
181         dp[i][2]=max(dp[i][2],dp[i][1]+dp[pre[i][0]-2][0]);
182     }
183     cout<<sumf[2*brtot-1]-dp[2*brtot-1][2]<<endl;
184 }
185 
186 int main()
187 {
188     cin>>t;
189     for (k=1;k<=t;k++)
190     {
191         cin>>n>>m>>st>>en>>l;
192         for (i=0;i<=n-1;i++) hd[i]=-1;
193         tot=0;
194         memset(inp,0,sizeof(inp));
195         memset(outp,0,sizeof(outp));
196         for (i=1;i<=m;i++)
197         {
198             cin>>x>>y>>z;
199             ins(x,y,z);
200         }
201         
202         memset(fl,0,sizeof(fl));
203         memset(enfl,0,sizeof(enfl));
204         enfl[en]=1;
205         dfs(st);
206         if (enfl[st]==0) {cout<<-1<<endl; continue;}
207         for (i=0;i<=n-1;i++)
208             if (enfl[i]==0)
209             {
210                 j=hd[i];
211                 while (j!=-1)
212                 {
213                     outp[i]--; inp[e[j].to]--;
214                     j=e[j].next;
215                 }
216             }
217     
218         tuopu();
219         
220         findbridge();
221         
222         countt();
223     }
224 }
独(luan)特(gao)的做法

转载于:https://www.cnblogs.com/Krain428571/p/7368194.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值