UVa 1658 Admiral

来源:互联网 发布:单相四极电机绕组数据 编辑:程序博客网 时间:2024/04/25 13:53
Michiel Adriaenszoon de Ruyter is the most famous admiral in Dutch history and is well known for his
role in the Anglo-Dutch Wars of the 17th century. De Ruyter personally commanded a flagship and
issued commands to allied warships during naval battles.
In De Ruyter’s time, graph theory had just been invented and the admiral used it to his great
advantage in planning his naval battles. Waypoints at sea are represented by vertices, and possible
passages from one waypoint to another are represented as directed edges. Given any two waypoints
W1 and W2 , there is at most one passage W1 → W2 . Each directed edge is marked with the number
of cannonballs that need to be fired in order to safely move a ship along that edge, sinking the enemy
ships encountered along the way.
One of De Ruyter’s most successful tactics was the De Ruyter Manoeuvre. Here, two warships start
at the same waypoint, and split up and fight their way through the enemy fleet, joining up again at a
destination waypoint. The manoeuvre prescribes that the two warships take disjunct routes, meaning
that they must not visit the same waypoint (other than the start and end-points), or use the same
passage during the battle.
Being Dutch, Admiral De Ruyter did not like to waste money; in 17th century naval warfare, this
meant firing as few expensive cannonballs as possible.
Figure 1: A particular instance of De Ruyter’s tactic, visualised as a graph. Two ships (‘red’
and ‘blue’) move from a shared starting point (1) to a shared endpoint (6). The red ship’s route is
1 → 3 → 6 (firing 33 canonballs along the way); the blue ship’s route is 1 → 2 → 5 → 4 → 6 (firing
53 canonballs along the way). In total, 86 canonballs are fired during the manoeuvre. Except for the
start- and end-point, no vertices or edges are visited by both ships.
Input
For each test case, the input consists of:
• A line containing two integers v (3 ≤ v ≤ 1000) and e (3 ≤ e ≤ 10000), the number of waypoints
and passages, respectively.
• Then, e lines follow: for each passage, a line containing three integers:
1. ai (1 ≤ ai ≤ v), the starting-point of a passage, which is represented by a waypoint;
2. bi (1 ≤ bi ≤ v) and (ai ̸= bi), the end-point of a passage, which is represented by a waypoint.
All passages are directed passages;
3. ci (1 ≤ ci ≤ 100), the number of cannonballs that are fired when travelling along this passage.
The starting waypoint is 1 and the destination waypoint is v. There are always at least two disjunct
routes from waypoint 1 to waypoint v.
Output
For each test case, the output consists of a single positive integer: the smallest possible sum of cannonballs
fired by both ships when reaching the destination waypoint.
Sample Input
6 11
1 2 23
1 3 12
1 4 99
2 5 17
2 6 73
3 5 3
3 6 21
4 6 8
5 2 33
5 4 5
6 5 20
Sample Output

86

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

费用流+拆点~

还是MCMF算法~

因为求的是两条路线之和,所以要把每个点拆成两个点建图,比如吧i点拆成i和i+n来看,i和i+n之间连一条边,边权为1,花费为0,再跑一遍费用流就好了~


#include<cstdio>#include<cstring>#include<iostream>#include<vector>#include<queue>using namespace std;#define ll long long#define inf 999999999int n,m,x,y,val,ne[2010],tot,dis[2010],a[2010];ll flow,cost;bool b[2010];struct edge{int x,y,cap,flow,cost;edge(int u,int v,int k,int z,int kkz):x(u),y(v),cap(k),flow(z),cost(kkz) {}};vector<edge> ed;vector<int> p[2010];void add(int u,int v,int k,int z){ed.push_back(edge(u,v,k,0,z));ed.push_back(edge(v,u,0,0,-z));int kkz=ed.size();p[u].push_back(kkz-2);p[v].push_back(kkz-1);}bool findd(){for(int i=1;i<=tot;i++) dis[i]=inf;queue<int> q;q.push(1);dis[1]=0;a[1]=inf;b[1]=1;while(!q.empty()){int k=q.front();q.pop();b[k]=0;int now=p[k].size();for(int i=0;i<now;i++){edge z=ed[p[k][i]];if(z.cap>z.flow && dis[z.y]>dis[k]+z.cost){a[z.y]=min(a[k],z.cap-z.flow);ne[z.y]=p[k][i];dis[z.y]=dis[k]+z.cost;if(!b[z.y]){b[z.y]=1;q.push(z.y);}}}}if(dis[tot]==inf) return 0;flow+=(ll)a[tot];cost+=(ll)a[tot]*(ll)dis[tot];for(int i=tot;i!=1;i=ed[ne[i]].x){ed[ne[i]].flow+=a[tot];ed[ne[i]^1].flow-=a[tot];}return 1;}ll flowfindd(){flow=cost=0;while(findd());return cost;}int main(){while(scanf("%d%d",&n,&m)!=EOF){ed.clear();tot=n<<1;for(int i=1;i<=tot;i++) p[i].clear();for(int i=2;i<n;i++) add(i,i+n,1,0);add(1,n+1,2,0);add(n,tot,2,0);for(int i=1;i<=m;i++){scanf("%d%d%d",&x,&y,&val);add(x+n,y,1,val);}printf("%lld\n",flowfindd());}return 0;}


1 0