bzoj1927

题意:给定一个图,还有一些有向边,每条边有一个权值w。对于每一个点,可以从其他任意一个点转移到这个点,时间为t。求从图外的一个点(即第一次一定是通过转移方式),遍历图中每个点一次最少需要的时间。。

思路:

对于图中的每个点,需要满足的要求是进入一次,出去一次(即遍历一边)

所以我们很容易想到拆点,把每个点拆成两个点。建图如下:

<S, i, 1, 0>对应每个点进入一次

<i+n, T, 1, 0>对应每个点出去一次

<i, j + n, 1, wij>,如果ij有边对应i走到j

<S, i, 1, t[i]>对应可以从其他点转移到这个点

这样跑一遍最小费用流就是答案。

code:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define M0(a) memset(a, 0, sizeof(a))
 4 #define Inf 0x3fffffff
 5 const int maxn = 2010;
 6 const int maxm = 200010;
 7 struct edge{
 8      int v, f, c, next;
 9      edge(){}
10      edge(int _v, int _f, int _c, int _next):v(_v), f(_f), c(_c), next(_next){}
11 };
12 struct Costflow{
13      int last[maxn], pre[maxn], dis[maxn], vis[maxn];
14      int tot, S, T;
15      edge e[maxm];
16      void add(int u, int v, int f, int c){
17           e[tot] = edge(v, f, c, last[u]); last[u] = tot++;
18           e[tot] = edge(u, 0, -c, last[v]); last[v] = tot++;
19      }
20      void init(int S, int T){
21           this->S = S, this->T = T;
22           M0(e);
23           memset(last, -1, sizeof(last));
24           tot = 0;
25      }
26      int spfa(){
27           for (int i = 0; i <= T; ++i)
28               dis[i] = Inf;
29           memset(vis, 0, sizeof(vis));
30           memset(pre, -1, sizeof(pre));
31           dis[S] = 0;
32           queue<int> q;
33           q.push(S) , vis[S] = 1;
34           int p, u, v;
35           while (!q.empty()){
36                 p = last[u = q.front()];
37                 for ( ; p > -1; p = e[p].next){
38                        v = e[p].v;
39                        if (dis[u] + e[p].c < dis[v] && e[p].f > 0){
40                              dis[v] = dis[u] + e[p].c;
41                              pre[v] = p;
42                              if (!vis[v]) vis[v] = 1, q.push(v);
43                        }
44                 }
45                 vis[u] = 0;
46                 q.pop();
47           }
48           return dis[T] < Inf;
49      }
50      int costflow(){
51           int cost = 0, flow = 0;
52           while (spfa()){
53                int f = Inf;
54                for (int p = pre[T]; p != -1; p = pre[e[p^1].v])
55                       f = min(f, e[p].f);
56                flow += f;
57                cost += f * dis[T];
58                for (int p = pre[T]; p != -1; p = pre[e[p^1].v])
59                       e[p].f -= f, e[p^1].f += f;
60           }
61           return cost;
62      }
63      /***********/
64 } F;
65 int n, m;
66 int t[maxn];
67
68 void solve(){
69 //     printf("%d %d\n", n, m);
70      for (int i = 1; i <= n; ++i)
71          scanf("%d", t+i);
72      int S = 0, T = 2 * n + 1;
73      F.init(S, T);
74      for (int i = 1; i <= n; ++i)
75          F.add(S, i + n, 1, t[i]), F.add(i+n, T, 1, 0), F.add(S, i, 1, 0);
76      int u, v, w;
77      for (int i = 1; i <= m; ++i){
78          scanf("%d%d%d", &u, &v, &w);
79          if (u > v) swap(u, v);
80          F.add(u, v+n, 1, w);
81      }
82      int ans = F.costflow();
83      cout << ans << endl;
84 }
85
86 int main(){
87     while (scanf("%d%d", &n, &m) != EOF){
88         solve();
89     }
90 }

时间: 2024-10-09 12:24:11

bzoj1927的相关文章

bzoj1927: [Sdoi2010]星际竞速

跟上一题几乎一样... #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) #define op() clr(head

【bzoj1927】[Sdoi2010]星际竞速 有上下界费用流

原文地址:http://www.cnblogs.com/GXZlegend/p/6832464.html 题目描述 10年一度的银河系赛车大赛又要开始了.作为全银河最盛大的活动之一,夺得这个项目的冠军无疑是很多人的梦想,来自杰森座α星的悠悠也是其中之一.赛车大赛的赛场由N颗行星和M条双向星际航路构成,其中每颗行星都有一个不同的引力值.大赛要求车手们从一颗与这N颗行星之间没有任何航路的天体出发,访问这N颗行星每颗恰好一次,首先完成这一目标的人获得胜利.由于赛制非常开放,很多人驾驶着千奇百怪的自制赛

【Bzoj1927】星际竞速(费用流)

Description 题意:给定n个点m条边的无向图,只能从编号小的到编号大的,且要求经过所有点刚好一次,而且可以从任意点瞬移到i号点并花费代价Ai,求最小代价. n<=800,m<=15000 Solution Code #include <cstdio> #include <algorithm> #include <queue> #define N 2010 #define Inf 0x7fffffff using namespace std; str

20160522~20160528

20160523 bzoj2561 http://www.lydsy.com/JudgeOnline/problem.php?id=2561 题意:给定一个连通无向图,假设现在加入一条边权为L的边(u,v),求需要删掉最少多少条边,才能够使得这条边既可能出现在最小生成树上,也可能出现在最大生成树上.N≤20000,M≤200000 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4

【bzoj2324】[ZJOI2011]营救皮卡丘 最短路-Floyd+有上下界费用流

原文地址:http://www.cnblogs.com/GXZlegend/p/6832504.html 题目描述 皮卡丘被火箭队用邪恶的计谋抢走了!这三个坏家伙还给小智留下了赤果果的挑衅!为了皮卡丘,也为了正义,小智和他的朋友们义不容辞的踏上了营救皮卡丘的道路. 火箭队一共有N个据点,据点之间存在M条双向道路.据点分别从1到N标号.小智一行K人从真新镇出发,营救被困在N号据点的皮卡丘.为了方便起见,我们将真新镇视为0号据点,一开始K个人都在0号点. 由于火箭队的重重布防,要想摧毁K号据点,必须

bzoj网络流

近期看了一些bzoj的网络流,深感智商不够.不过对于网络流又有了进一步的理解. 还是mark一下吧. 献上几篇论文:1)<最小割模型在信息学竞赛中的应用> 2)<浅析一类最小割问题> 1.bzoj1066(最大流) 题意:戳这里 思路:很明显拆点最大流模型,然后对于每个点每个高度流量限为1,那么根据最大流即为可以出去的蜥蜴的数量. 2.bzoj1077(费用流) 戳这里 3.bzoj1391(最小割) 题意:戳这里 思路:有点像最大权闭合图..可以利用最小割的性质建图: <S

bzoj 2055 80人环游世界

有源汇上下界最小费用可行流. 将每个国家拆点. 源点向一个新建节点连一条上界为总人数下界为0费用为0的边. 新建节点向每个国家的入点连一条上界为正无穷下界为0费用为0的边. 每个国家的入点向出点连一条上下界均为该国家访问人数费用为0的边. 每个国家的出点向汇点连一条上界为正无穷下界为0费用为0的边. 对于国家i能到国家j,i的出点向j的入点连一条上界为正无穷下界为0费用为机票费的边. 然后对图求一边有源汇上下界最小费用可行流即可得出最小费用. 具体做法是先将所有边的下界乘费用相加,这一部分是必须

大神刷题表

9月27日 后缀数组:[wikioi3160]最长公共子串 dp:NOIP2001统计单词个数 后缀自动机:[spoj1812]Longest Common Substring II [wikioi3160]最长公共子串 [spoj7258]Lexicographical Substring Search 扫描线+set:[poj2932]Coneology 扫描线+set+树上删边游戏:[FJOI2013]圆形游戏 结论:[bzoj3706][FJ2014集训]反色刷 最小环:[poj1734

[转载]hzwer的bzoj题单

counter: 664BZOJ1601 BZOJ1003 BZOJ1002 BZOJ1192 BZOJ1303 BZOJ1270 BZOJ3039 BZOJ1191 BZOJ1059 BZOJ1202 BZOJ1051 BZOJ1001 BZOJ1588 BZOJ1208 BZOJ1491 BZOJ1084 BZOJ1295 BZOJ3109 BZOJ1085 BZOJ1041 BZOJ1087 BZOJ3038 BZOJ1821 BZOJ1076 BZOJ2321 BZOJ1934 BZOJ