题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5889
题意:
就是有2个城堡,1为A城堡, N为B敌人, 敌人要攻打A城堡,但我们知道敌人必定走 最短路,A城堡国王想设置障碍在这些最短路中,而且要使这些敌人必须经过1个障碍.可是现在是打仗时候,要尽量少用材料,
设置一个路障的花费为这段路的权值,求最少花费.
个人感想:
咋眼一看,咦这不是费用流吗.最大流,最小费用.我一开始看起来觉得没错啊,可是认真想了一想,肯定错的啊,因为最大流并不保证流的就是最短路径啊.而且人家都说了,他只会走最短路…那的怎么做啊?我也不太懂…
然后我看了下好多网上的题解,其实都是从原图中抽取最短路再跑最大流==最小割就好了,这又怎么抽啊,我一直都忽略的一个思想:可以通过dijkastra写好的dis数组来找到对应的路.因为我们就是从这些最短路中转移过来的,那么肯定绝对能找回原来的路径…至于大流吗,想想都知道就是把路不让他连通就好了,刚好久是最小割..
这题好有意思啊…涨姿势了…
分析:最短路+最大流
/* Author:GavinjouElephant
* Title:
* Number:
* main meanning:
*
*
*
*/
#include <iostream>
using namespace std;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <vector>
#include <set>
#include <cstdlib>
#include <map>
#include <queue>
//#include<initializer_list>
//#include <windows.h>
//#include <fstream>
//#include <conio.h>
#define MaxN 0x7fffffff
#define MinN -0x7fffffff
#define lson 2*k
#define rson 2*k+1
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=1e5+10;
int Scan()//读入整数外挂.
{
int res = 0, ch, flag = 0;
if((ch = getchar()) == '-') //判断正负
flag = 1;
else if(ch >= '0' && ch <= '9') //得到完整的数
res = ch - '0';
while((ch = getchar()) >= '0' && ch <= '9' )
res = res * 10 + ch - '0';
return flag ? -res : res;
}
void Out(int a) //输出外挂
{
if(a>9)
Out(a/10);
putchar(a%10+'0');
}
int T;
int N,M;
struct edge
{
int to;//到的节点
int d;
int cost;//花费
};
struct Edge
{
int to;
int cap;
int rev;
};
typedef pair<int,int> P;
vector<edge> G[1005];
vector<Edge> p2[1005];
int dis[1005];
int level[1005];
int iter[1005];
bool vis[1005];
void addedge(int u,int v,int cost)
{
edge tmp;
tmp.to=v;
tmp.d=1;
tmp.cost=cost;
G[u].push_back(tmp);
tmp.to=u;
tmp.d=1;
tmp.cost=cost;
G[v].push_back(tmp);
}
void dijkastra(int s)
{
priority_queue<P,vector<P>,greater<P> >que;
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
que.push(P(0,s));
while(!que.empty())
{
P p=que.top();
que.pop();
int v=p.second;
if(dis[v]<p.first) continue;
for(int i=0;i<G[v].size();i++)
{
edge e=G[v][i];
//cout<<v<<"->"<<e.to<<endl;
if(dis[e.to]>dis[v]+e.d)
{
dis[e.to]=dis[v]+e.d;
que.push(P(dis[e.to],e.to));
}
}
}
}
void add_edge(int from,int to,int cap)
{
// cout<<from<<"->"<<to<<" "<<cap<<endl;
p2[from].push_back((Edge){to,cap,p2[to].size()});
p2[to].push_back((Edge){from,0,p2[from].size()-1});
}
void bfs(int s)
{
memset(level,-1,sizeof(level));
queue<int> que;
level[s]=0;
que.push(s);
while(!que.empty())
{
int v=que.front();
que.pop();
for(int i=0;i<p2[v].size();i++)
{
Edge &e=p2[v][i];
if(e.cap>0 && level[e.to]<0)
{
level[e.to]=level[v]+1;
que.push(e.to);
}
}
}
}
int dfs(int v,int t,int f)
{
if(v==t) return f;
for(int &i=iter[v];i<p2[v].size();i++)
{
Edge &e=p2[v][i];
if(e.cap>0&&level[v]<level[e.to])
{
int d=dfs(e.to,t,min(f,e.cap));
if(d>0)
{
e.cap-=d;
p2[e.to][e.rev].cap +=d;
return d;
}
}
}
return 0;
}
int max_flow(int s,int t)
{
int flow=0;
for(;;)
{
bfs(s);
if(level[t]<0)return flow;
memset(iter,0,sizeof(iter));
int f;
while((f=dfs(s,t,INF))>0)
{
flow+=f;
}
}
return flow;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("coco.txt","r",stdin);
freopen("lala.txt","w",stdout);
#endif
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&N,&M);
for(int i=0;i<=N;i++) {G[i].clear();p2[i].clear();}
for(int i=0;i<M;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z);
}
dijkastra(N);
memset(vis,0,sizeof(vis));
queue<int> que;
que.push(1);
vis[1]=true;
while(!que.empty())
{
int s=que.front();
que.pop();
for(int j=0;j<G[s].size();j++)
{
edge &e=G[s][j];
int son=e.to;
if(dis[s]-1==dis[son])
{
if(!vis[son])
{
que.push(son);
vis[son]=true;
}
add_edge(s,son,e.cost);
}
}
}
printf("%d\n",max_flow(1,N));
}
return 0;
}