总算今天静下心来学算法。。

Description

Innocent Wu follows Dumb Zhang into a ancient tomb. Innocent Wu’s at the entrance of the tomb while Dumb Zhang’s at the end of it. The tomb is made up of many chambers, the total number is N. And there are M channels connecting the chambers. Innocent Wu wants to catch up Dumb Zhang to find out the answers of some questions, however, it’s Dumb Zhang’s intention to keep Innocent Wu in the dark, to do which he has to stop Innocent Wu from getting him. Only via the original shortest ways from the entrance to the end of the tomb costs the minimum time, and that’s the only chance Innocent Wu can catch Dumb Zhang. 
Unfortunately, Dumb Zhang masters the art of becoming invisible(奇门遁甲) and tricks devices of this tomb, he can cut off the connections between chambers by using them. Dumb Zhang wanders how many channels at least he has to cut to stop Innocent Wu. And Innocent Wu wants to know after how many channels at most Dumb Zhang cut off Innocent Wu still has the chance to catch Dumb Zhang. 
 

Input

There are multiple test cases. Please process till EOF. 
For each case,the first line must includes two integers, N(<=2000), M(<=60000). N is the total number of the chambers, M is the total number of the channels. 
In the following M lines, every line must includes three numbers, and use ai、bi、li as channel i connecting chamber ai and bi(1<=ai,bi<=n), it costs li(0<li<=100) minute to pass channel i. 
The entrance of the tomb is at the chamber one, the end of tomb is at the chamber N. 
 

Output

Output two numbers to stand for the answers of Dumb Zhang and Innocent Wu’s questions.
 

Sample Input

8 9
1 2 2
2 3 2
2 4 1
3 5 3
4 5 4
5 8 1
1 6 2
6 7 5
7 8 1
 

Sample Output

2 6
 
题意:给出一幅无向图,n个点m条边。规定 1 为起点,n 为终点。问,若走最短路(可能不止一条),最少删去几条边使得起点与终点不连通,最多删去几条边使得仍然连通。
 
思路:
对于第一个问题,先跑一遍最短路,然后用最短路重新构图。构图方式有二:一是判 d[i]-d[j]==e[i][j],是则加入新图。二是最短路结点的儿子或者父亲,然后依次加入新图。之后,跑一遍最大流求最小割即可。
对于第二个问题,只要在跑最短路的时候,用 num 数组记录维护到当前结点经过的边数即可。初始化num[1]=0;
注意有重边、多边等情况,用邻接表存图。
 
分别用 EdmondsKarp 和 Dinic 做了遍。
前者的复杂度上界为O(nm*m),后者为O(n*nm)。
但大概数据比较和谐,前者也过了。
 
重新构图的时候注意对应点和边。比如最后才找到的bug:
for(int i=;i<=n;i++){
for(int j=;j<g[i].size();j++){
int tmp=d[i]-d[g[i][j]];
if(tmp<) tmp=-tmp;
if(tmp==e[i][j])
addEdge(i,g[i][j],e[i][j]);
}
}

举个例子:i 结点在最短路中前于 j 结点,e[i][j] 表示从 j 到 i 到有向边权值,则 d[i]-d[j]<0,则判了 d[j]-d[i]==e[i][j],错误。这在某些情况下回使得新建的图多了一条边。

正确的姿势如下:
for(int i=;i<=n;i++){
for(int j=;j<g[i].size();j++){
if(d[i]+e[i][j]==d[j])
addEdge(i,g[i][j],e[i][j]);
}
}

最小割的定义和求法:

定义:设点集S,T,称将起点在 S 中,终点在 T 中 的所有边删除后将使得 s 无法到达 t 的的集合划分(S,T)称为一个 s-t 割。(s 在 S 中 t 在 T 中)

在求得最大流后,寻找增广路过程中标记的点为集合 S,其余点为 T ,即得最小割。

最小割中的边数即为第一问的答案。(详情见代码)

对数组设置上界的时候:memset(n_g,0x3f,sizeof(n_g));//每个数都为0x3f3f3f3f。
以下两份代码进一步优化的途径:
1.用数组完成邻接表存图,避免 vector 的 clear 和 push_back;
2.求最短路时,用优先队列优化Dijkstra,或者用spfa算法。
3.用数组模拟队列,这里没有必要模拟环形队列。
其它有待补充。
 
EdmondsKarp:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define maxn 2015
#define inf 0x3f3f3f3f
struct Edge{
int from,to,cap,flow;
Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
vector<Edge>E;
vector<int>g[maxn],e[maxn],G[maxn];
int n,m,M,a,b,c,d[maxn],vis[maxn],num[maxn],bet[maxn],p[maxn];
void init(){
for(int i=;i<=n;i++)
g[i].clear(),e[i].clear(),G[i].clear();
E.clear();
memset(vis,,sizeof(vis));
}
void addEdge(int from,int to,int cap){
E.push_back(Edge(from,to,cap,));
E.push_back(Edge(to,from,,));
M=E.size();
G[from].push_back(M-);
G[to].push_back(M-);
}
void maxflow(int s,int t){
for(;;){
memset(bet,,sizeof(bet));
queue<int>q;
q.push(s);
bet[s]=inf;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=;i<G[x].size();i++){
Edge &ee=E[G[x][i]];
if(!bet[ee.to]&&ee.cap>ee.flow){
p[ee.to]=G[x][i];
bet[ee.to]=min(bet[x],ee.cap-ee.flow);
q.push(ee.to);
}
}
if(bet[t]) break;
}
if(!bet[t]) break;
for(int u=t;u!=s;u=E[p[u]].from){
E[p[u]].flow+=bet[t];
E[p[u]^].flow-=bet[t];
}
}
}
void Dijk(){
memset(d,0x3f,sizeof(d));
memset(num,0x3f,sizeof(num));
d[]=num[]=;
for(int i=;i<=n;i++){
int u=-;
for(int j=;j<=n;j++) if(!vis[j]){
if(u==-||d[j]<d[u]) u=j;
}
vis[u]=;
for(int j=;j<g[u].size();j++) if(!vis[g[u][j]]){
int tmp=d[u]+e[u][j];
if(tmp==d[g[u][j]]) num[g[u][j]]=min(num[u]+,num[g[u][j]]);
if(tmp<d[g[u][j]]){
d[g[u][j]]=tmp;
num[g[u][j]]=num[u]+;
}
}
}
}
int main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
//freopen("test.txt","r",stdin);
while(~scanf("%d%d",&n,&m)){
init();
for(int i=;i<m;i++){
scanf("%d%d%d",&a,&b,&c);
g[a].push_back(b),e[a].push_back(c);
g[b].push_back(a),e[b].push_back(c);
}
Dijk();
int ans1=,ans2=m-num[n];
for(int i=;i<=n;i++){
for(int j=;j<g[i].size();j++){
if(e[i][j]+d[i]==d[g[i][j]])
addEdge(i,g[i][j],e[i][j]);
}
}
maxflow(,n);
for(int i=;i<E.size();i++){
Edge &ee=E[i];
if(bet[ee.from]&&!bet[ee.to]&&ee.cap>) ans1++;
}
printf("%d %d\n",ans1,ans2);
}
return ;
}

以及Dinic:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define maxn 2015
#define inf 0x3f3f3f3f
struct Edge{
int from,to,cap,flow;
Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
vector<Edge>E;
vector<int>g[maxn],e[maxn],G[maxn];
int n,m,M,a,b,c,d[maxn],vis[maxn],num[maxn],cur[maxn],dis[maxn];
void init(){
for(int i=;i<=n;i++)
g[i].clear(),e[i].clear(),G[i].clear();
E.clear();
memset(vis,,sizeof(vis));
}
void addEdge(int from,int to,int cap){
E.push_back(Edge(from,to,cap,));
E.push_back(Edge(to,from,,));
M=E.size();
G[from].push_back(M-);
G[to].push_back(M-);
}
bool bfs(){
memset(vis,,sizeof(vis));
queue<int>q;
q.push();
dis[]=;
vis[]=;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=;i<G[x].size();i++){
Edge &ee=E[G[x][i]];
if(!vis[ee.to]&&ee.cap>ee.flow){
vis[ee.to]=;
dis[ee.to]=dis[x]+;
q.push(ee.to);
}
}
}
return vis[n];
}
int dfs(int x,int a){
if(x==n||a==) return a;
int flow=,f;
for(int &i=cur[x];i<G[x].size();i++){
Edge &ee=E[G[x][i]];
if(dis[x]+==dis[ee.to]&& (f=dfs(ee.to,min(a,ee.cap-ee.flow)))>){
ee.flow+=f;
E[G[x][i]^].flow-=f;
flow+=f;
a-=f;
if(a==) break;
}
}
return flow;
}
void maxflow(){
while(bfs()){
memset(cur,,sizeof(cur));
dfs(,inf);
}
}
void Dijk(){
memset(d,0x3f,sizeof(d));
memset(num,0x3f,sizeof(num));
d[]=num[]=;
for(int i=;i<=n;i++){
int u=-;
for(int j=;j<=n;j++) if(!vis[j]){
if(u==-||d[j]<d[u]) u=j;
}
vis[u]=;
for(int j=;j<g[u].size();j++) if(!vis[g[u][j]]){
int tmp=d[u]+e[u][j];
if(tmp==d[g[u][j]]) num[g[u][j]]=min(num[u]+,num[g[u][j]]);
if(tmp<d[g[u][j]]){
d[g[u][j]]=tmp;
num[g[u][j]]=num[u]+;
}
}
}
}
int main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
//freopen("test.txt","r",stdin);
while(~scanf("%d%d",&n,&m)){
init();
for(int i=;i<m;i++){
scanf("%d%d%d",&a,&b,&c);
g[a].push_back(b),e[a].push_back(c);
g[b].push_back(a),e[b].push_back(c);
}
Dijk();
int ans1=,ans2=m-num[n];
for(int i=;i<=n;i++){
for(int j=;j<g[i].size();j++){
if(d[i]+e[i][j]==d[g[i][j]])
addEdge(i,g[i][j],e[i][j]);
}
}
maxflow();
for(int i=;i<E.size();i++){
Edge &ee=E[i];
if(ee.from==ee.to) continue;
if(vis[ee.from]&&!vis[ee.to]&&ee.cap>) ans1++;
}
printf("%d %d\n",ans1,ans2);
}
return ;
}
 

2015 多校赛 第一场 1007 (hdu 5294)的更多相关文章

  1. 2015 多校赛 第一场 1002 (hdu 5289)

    Description Tom owns a company and he is the boss. There are n staffs which are numbered from 1 to n ...

  2. 2015 多校赛 第一场 1001 (hdu 5288)

    Description OO has got a array A of size n ,defined a function f(l,r) represent the number of i (l&l ...

  3. hdu5294||2015多校联合第一场1007 最短路+最大流

    http://acm.hdu.edu.cn/showproblem.php? pid=5294 Problem Description Innocent Wu follows Dumb Zhang i ...

  4. 2015 多校赛 第二场 1006 (hdu 5305)

    Problem Description There are n people and m pairs of friends. For every pair of friends, they can c ...

  5. 2015 多校赛 第二场 1004 hdu(5303)

    Problem Description There are n apple trees planted along a cyclic road, which is L metres long. You ...

  6. 2015 多校赛 第二场 1002 (hdu 5301)

    Description Your current task is to make a ground plan for a residential building located in HZXJHS. ...

  7. hdu 5288||2015多校联合第一场1001题

    pid=5288">http://acm.hdu.edu.cn/showproblem.php?pid=5288 Problem Description OO has got a ar ...

  8. 2019牛客多校赛第一场 补题 I题

    I题  Points Division 题意: 给你n个点,每个点有坐标(xi,yi)和属性(ai,bi),将点集划分为两个集合, 任意 A 集合的点 i 和 B 集合点 j, 不允许 xi > ...

  9. 2014多校第六场 1007 || HDU 4927 Series 1(杨辉三角组合数)

    题目链接 题意 : n个数,每操作一次就变成n-1个数,最后变成一个数,输出这个数,操作是指后一个数减前一个数得到的数写下来. 思路 : 找出几个数,算得时候先不要算出来,用式子代替,例如: 1 2 ...

随机推荐

  1. THREE.js代码备份——webgl - custom attributes [lines](自定义字体显示、控制字图的各个属性)

    <!DOCTYPE html> <html lang="en"> <head> <title>three.js webgl - cu ...

  2. NSURLCredential 代表认证结果证书?

    NSURLCredential 代表认证结果证书?

  3. 微信小程序跳转以及跳转的坑

    一.首先小程序的跳转方法有一下几种 js控制跳转 // 保留当前页面,跳转到应用内的某个页面 wx.navigateTo({ url: '../blueberry/blueberry' }); // ...

  4. matlab学习滚动条改变文本数值

    如下分别添加滚动条,静态文本框和可编辑文本框,字体大小改为10,string值按下图,并使用对齐工具 保存名为GUI_02,会自动出来一个.m文件 注意代码一个字都不要错 %定义变量var,保存滚动条 ...

  5. [Java]链表的打印,反转与删除

    class Node{ public int value; public Node next=null; public Node(int value) { this.value=value; } }p ...

  6. XML的解析方式

    //解析和输出XML public void showXml() { string filepath = Application.dataPath + @"/my.xml"; if ...

  7. 【双系统】windows 和 Ubuntu 双系统安装

      本博客主要讲述如何在已安装windows系统的计算机上安装Ubuntu双系统,涉及系统安装和相应磁盘空间分配等问题. 所需环境: 电脑已安装windows系统 下载Ubuntu16.04系统镜像 ...

  8. vfs:open.c 源码学习

    nameidata路径查找辅助结构 open.c @do_sys_open @get_unused_fd_flags @do_filp_open 1.开始填充nameidata 2.开始填充file ...

  9. C#第六节课

    for循环 using System;using System.Collections.Generic;using System.Linq;using System.Text;using System ...

  10. 爬虫系列(二) Chrome抓包分析

    在这篇文章中,我们将尝试使用直观的网页分析工具(Chrome 开发者工具)对网页进行抓包分析,更加深入的了解网络爬虫的本质与内涵 1.测试环境 浏览器:Chrome 浏览器 浏览器版本:67.0.33 ...