Our Journey of Dalian Ends【网络流】
2017-09-11 19:11
453 查看
题意:从大连到西安,中间必须经过上海,每个城市只能经过一次,问最短路径
思路:每个点拆成入点、出点,连一条费用0,容量1的边。超级源点连大连、西安的入点,汇点是上海的入点。跑一边最小费用最大流。最大流为2,就输出最小费用;否则-1.
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<stdlib.h>
#include<math.h>
#include<vector>
#include<list>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<algorithm>
#include<numeric>
#include<functional>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 4e4+5;
map<string,int> ma;
struct edge
{
int to,cf,w,rev;
};
int d[maxn],fa[maxn],inq[maxn],pr[maxn];
vector<struct edge> v[maxn];
void init(int x)
{
for(int i = 0; i <= x; i++)
v[i].clear();
}
void add(int from,int to,int cap,int cost)
{
v[from].push_back((edge){to,cap,cost,v[to].size()});
v[to].push_back((edge){from,0,-cost,v[from].size()-1});
}
pii mincost(int s,int t)
{
queue<int> q;
while(!q.empty())
q.pop();
int c,f;
c = f = 0;
while(1)
{
memset(fa,-1,sizeof fa);
memset(d,0x3f,sizeof d);
d[s] = 0;
memset(inq,0,sizeof inq);
q.push(s);
while(!q.empty())
{
int x = q.front();q.pop();
inq[x] = 0;
for(int i = 0; i < v[x].size(); i++)
{
edge e = v[x][i];
int y = e.to;
if(e.cf && d[y] > d[x] + e.w)
{
d[y] = d[x] + e.w;
fa[y] = x;
pr[y] = i;
if(!inq[y])
{
inq[y] = 1;
q.push(y);
}
}
}
}
if(d[t] == 0x3f3f3f3f) //改成ll后用 0x3f3f3f3f3f3f3f3f
break;
int gen = 0x3f3f3f3f;
for(int a = t; a != s; a = fa[a])
gen = min(gen,v[fa[a]][pr[a]].cf);
for(int a = t; a != s; a = fa[a])
{
edge &e = v[fa[a]][pr[a]];
e.cf -= gen;
v[a][e.rev].cf += gen;
}
f += gen;
c += gen * d[t];
}
pii a
4000
ns = make_pair(c,f);
return ans;//f 最大流,c最小费用
}
int main(void)
{
int T,m,s,t,cnt,val;
string a,b;
scanf("%d",&T);
while(T--)
{
scanf("%d",&m);
init(2*m+5);
ma.clear();
cnt = 1;
for(int i = 0; i < m; i++)
{
cin>>a>>b;
scanf("%d",&val);
if(ma.find(a) == ma.end())
{
ma[a] = cnt;
s = cnt;
cnt += 2;
}
else
s = ma[a];
if(ma.find(b) == ma.end())
{
ma[b] = cnt;
t = cnt;
cnt += 2;
}
else
t = ma[b];
add(s+1,t,1,val);
add(t+1,s,1,val);
}
if(ma.find("Dalian")==ma.end() || ma.find("Shanghai")==ma.end() || ma.find("Xian")==ma.end())
{
printf("-1\n");
continue;
}
for(int i = 1; i < cnt; i += 2)
add(i,i+1,1,0);
add(0,ma["Dalian"],1,0);
add(0,ma["Xian"],1,0);
pii ans = mincost(0,ma["Shanghai"]);
if(ans.second == 2)
printf("%d\n",ans.first);
else
printf("-1\n");
}
return 0;
}
/*
3
2
Dalian Shanghai 3
Shanghai Xian 4
5
Dalian Shanghai 7
Shanghai N 1
Dalian N 3
N Xian 5
Shanghai Xian 8
3
Dalian NanJng 6
Shanghai NanJing 7
NanJing Xian 8
*/
思路:每个点拆成入点、出点,连一条费用0,容量1的边。超级源点连大连、西安的入点,汇点是上海的入点。跑一边最小费用最大流。最大流为2,就输出最小费用;否则-1.
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<stdlib.h>
#include<math.h>
#include<vector>
#include<list>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<algorithm>
#include<numeric>
#include<functional>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 4e4+5;
map<string,int> ma;
struct edge
{
int to,cf,w,rev;
};
int d[maxn],fa[maxn],inq[maxn],pr[maxn];
vector<struct edge> v[maxn];
void init(int x)
{
for(int i = 0; i <= x; i++)
v[i].clear();
}
void add(int from,int to,int cap,int cost)
{
v[from].push_back((edge){to,cap,cost,v[to].size()});
v[to].push_back((edge){from,0,-cost,v[from].size()-1});
}
pii mincost(int s,int t)
{
queue<int> q;
while(!q.empty())
q.pop();
int c,f;
c = f = 0;
while(1)
{
memset(fa,-1,sizeof fa);
memset(d,0x3f,sizeof d);
d[s] = 0;
memset(inq,0,sizeof inq);
q.push(s);
while(!q.empty())
{
int x = q.front();q.pop();
inq[x] = 0;
for(int i = 0; i < v[x].size(); i++)
{
edge e = v[x][i];
int y = e.to;
if(e.cf && d[y] > d[x] + e.w)
{
d[y] = d[x] + e.w;
fa[y] = x;
pr[y] = i;
if(!inq[y])
{
inq[y] = 1;
q.push(y);
}
}
}
}
if(d[t] == 0x3f3f3f3f) //改成ll后用 0x3f3f3f3f3f3f3f3f
break;
int gen = 0x3f3f3f3f;
for(int a = t; a != s; a = fa[a])
gen = min(gen,v[fa[a]][pr[a]].cf);
for(int a = t; a != s; a = fa[a])
{
edge &e = v[fa[a]][pr[a]];
e.cf -= gen;
v[a][e.rev].cf += gen;
}
f += gen;
c += gen * d[t];
}
pii a
4000
ns = make_pair(c,f);
return ans;//f 最大流,c最小费用
}
int main(void)
{
int T,m,s,t,cnt,val;
string a,b;
scanf("%d",&T);
while(T--)
{
scanf("%d",&m);
init(2*m+5);
ma.clear();
cnt = 1;
for(int i = 0; i < m; i++)
{
cin>>a>>b;
scanf("%d",&val);
if(ma.find(a) == ma.end())
{
ma[a] = cnt;
s = cnt;
cnt += 2;
}
else
s = ma[a];
if(ma.find(b) == ma.end())
{
ma[b] = cnt;
t = cnt;
cnt += 2;
}
else
t = ma[b];
add(s+1,t,1,val);
add(t+1,s,1,val);
}
if(ma.find("Dalian")==ma.end() || ma.find("Shanghai")==ma.end() || ma.find("Xian")==ma.end())
{
printf("-1\n");
continue;
}
for(int i = 1; i < cnt; i += 2)
add(i,i+1,1,0);
add(0,ma["Dalian"],1,0);
add(0,ma["Xian"],1,0);
pii ans = mincost(0,ma["Shanghai"]);
if(ans.second == 2)
printf("%d\n",ans.first);
else
printf("-1\n");
}
return 0;
}
/*
3
2
Dalian Shanghai 3
Shanghai Xian 4
5
Dalian Shanghai 7
Shanghai N 1
Dalian N 3
N Xian 5
Shanghai Xian 8
3
Dalian NanJng 6
Shanghai NanJing 7
NanJing Xian 8
*/
相关文章推荐
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 J. Our Journey of Dalian Ends [网络流]
- 计蒜客-乌鲁木齐网络赛&费用流&拆点-Our Journey of Dalian Ends
- Our Journey of Dalian Ends (最小费用最大流)
- 计蒜客-2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛-J-Our Journey of Dalian Ends
- J: Our Journey of Dalian Ends
- 计蒜客:2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛:Our Journey of Dalian Ends
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 - J Our Journey of Dalian Ends(最小费用最大流)
- 计蒜客 Our Journey of Dalian Ends 拆点+最小费用最大流
- Our Journey of Dalian Ends 乌鲁木齐网络赛 最小费用最大流
- 计蒜客 16959 Our Journey of Dalian Ends(最小费用最大流-mcmf)
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 [计蒜客] Our Journey of Dalian Ends
- 计蒜客 Our Journey of Dalian Ends 最小费用最大流
- 【2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛】 J Our Journey of Dalian Ends 【拆点费用流】
- Our Journey of Dalian Ends
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 J.Our Journey of Dalian Ends【最小费用最大流】
- 【2017新疆网络赛】Our Journey of Dalian Ends 费用流
- 计蒜客 Our Journey of Dalian Ends(17新疆网赛) 费用流(思维建图)
- 计蒜客 16959 Our Journey of Dalian Ends(2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 J)
- ACM ICPC 乌鲁木齐网络赛 J. Our Journey of Dalian Ends
- 2017ACM-ICPC 青岛 K.Our Journey of Xian Ends