JAG Kingdom is a strange kingdom such that its N cities are connected only by one-way roads. The N cities are numbered 1 through N. ICPC (International Characteristic Product Corporation) transports its products from the factory at the city S to the storehouse at the city T in JAG Kingdom every day. For efficiency, ICPC uses multiple trucks at once. Each truck starts from S and reaches T on the one-way road network, passing through some cities (or directly). In order to reduce risks of traffic jams and accidents, no pair of trucks takes the same road. Now, ICPC wants to improve the efficiency of daily transports, while ICPC operates daily transports by as many trucks as possible under the above constraint. JAG Kingdom, whose finances are massively affected by ICPC, considers to change the direction of one-way roads in order to increase the number of trucks for daily transports of ICPC. Because reversal of many roads causes confusion, JAG Kingdom decides to reverse at most a single road. If there is no road such that reversal of the road can improve the transport efficiency, JAG Kingdom need not reverse any roads. Check whether reversal of a single road can improve the current maximum number of trucks for daily transports. And if so, calculate the maximum number of trucks which take disjoint sets of roads when a one-way road can be reversed, and the number of roads which can be chosen as the road to be reversed to realize the maximum. |
JAG Practice Contest for ACM-ICPC Asia Regional 2014 题意:给一个有向图,n个点,m条边,起点S ,终点T。现有很多个机器人要从S走到T,每条边只能走一个机器人,现要可以改一条边的方向,问最多有多少个机器人可以从S走到T,并且有多少种改法。(如果没有改变边的方向,则改法为0。) 解题:如要没有加条件:可以改一条边。那么这题就是找最多有多少条路要以从起点S走到T。建图:每条有向边的边权为1,用最大流跑一次。那么现在要改一条边的方向:如果要更改的边是走过的边,那么不会使走法增加,有可以还使路的条数减少,所以改的边一定不是满流的边(即走过的边),现在要改变一条不在走过的边< u , v >变成<v , u>,使得可以增流,那么只要从S沿着没有走过的边到 v ,再从u沿着没有走过的边 到 T,这样就可以使得路的条数增多。那么这样我们就可以用BFS标记 SF[] 能从S点沿着最大流每条边的残流量>0的边走到的一些点V,再标记 TF[] 能从T点沿着最大流每条边的残流量==0的边走到一些点U(即表示:能从U沿着那些边走到T)。最后只要枚举原来不在走过的边<u , v >,如果:SF[v]==1&&TF[u]==1则改变此边方向可以增流,方案数k+1。最后的最多机器人数ans = maxflow + k>0 ? 1 : 0 。 #include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define captype int
const int MAXN = 1010; //点的总数
const int MAXM = 40010; //边的总数
const int INF = 1<<30;
struct EDG{
int to,next;
captype cap;
} edg[MAXM];
int eid,head[MAXN];
int gap[MAXN]; //每种距离(或可认为是高度)点的个数
int dis[MAXN]; //每个点到终点eNode 的最短距离
int cur[MAXN]; //cur[u] 表示从u点出发可流经 cur[u] 号边
int pre[MAXN];
void init(){
eid=0;
memset(head,-1,sizeof(head));
}
//有向边 三个参数,无向边4个参数
void addEdg(int u,int v,captype c,captype rc=0){
edg[eid].to=v; edg[eid].next=head[u];
edg[eid].cap=c; head[u]=eid++;
edg[eid].to=u; edg[eid].next=head[v];
edg[eid].cap=rc; head[v]=eid++;
}
captype maxFlow_sap(int sNode,int eNode, int n){//n是包括源点和汇点的总点个数,这个一定要注意
memset(gap,0,sizeof(gap));
memset(dis,0,sizeof(dis));
memcpy(cur,head,sizeof(head));
pre[sNode] = -1;
gap[0]=n;
captype ans=0; //最大流
int u=sNode;
while(dis[sNode]<n){ //判断从sNode点有没有流向下一个相邻的点
if(u==eNode){ //找到一条可增流的路
for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to]){
edg[i].cap-=1;
edg[i^1].cap+=1; //可回流的边的流量
}
ans+=1;
u=sNode;
continue;
}
bool flag = false; //判断能否从u点出发可往相邻点流
int v;
for(int i=cur[u]; i!=-1; i=edg[i].next){
v=edg[i].to;
if(edg[i].cap>0 && dis[u]==dis[v]+1){
flag=true;
cur[u]=pre[v]=i;
break;
}
}
if(flag){
u=v;
continue;
}
//如果上面没有找到一个可流的相邻点,则改变出发点u的距离(也可认为是高度)为相邻可流点的最小距离+1
int Mind= n;
for(int i=head[u]; i!=-1; i=edg[i].next)
if(edg[i].cap>0 && Mind>dis[edg[i].to]){
Mind=dis[edg[i].to];
cur[u]=i;
}
gap[dis[u]]--;
if(gap[dis[u]]==0) return ans; //当dis[u]这种距离的点没有了,也就不可能从源点出发找到一条增广流路径
//因为汇点到当前点的距离只有一种,那么从源点到汇点必然经过当前点,然而当前点又没能找到可流向的点,那么必然断流
dis[u]=Mind+1;//如果找到一个可流的相邻点,则距离为相邻点距离+1,如果找不到,则为n+1
gap[dis[u]]++;
if(u!=sNode) u=edg[pre[u]^1].to; //退一条边
}
return ans;
}
bool flag[MAXM] , SF[MAXN] , TF[MAXN];
void bfs(int s ,bool flag)
{
queue<int>q;
int u , v;
q.push(s );
while(!q.empty())
{
u = q.front(); q.pop();
for(int i=head[u]; ~i ; i=edg[i].next)
{
v=edg[i].to;
if(flag)
{
if(SF[v]||!edg[i].cap)continue;
SF[v]=1;
q.push(v);
}
else{
if(TF[v]||!edg[i^1].cap)continue;
TF[v]=1;
q.push(v);
}
}
}
}
inline void scanf(int& num )
{
char ch;
while(ch=getchar())
{
if(ch>='0'&&ch<='9')break;
}
num = ch-'0';
while(ch=getchar())
{
if(ch<'0'||ch>'9')break;
num = num*10+ch-'0';
}
}
int main()
{
int n,m,vs , vt , u ,v;
while(scanf("%d%d%d%d",&n,&m,&vs,&vt)>0&&n+m+vs+vt!=0)
{
init();
for(int i=0; i<m; i++)
{
scanf(u);
scanf(v);
addEdg(u , v ,1);
}
memset(flag , 0 , (m+3)*sizeof(bool));
memset(SF,0,sizeof(SF));
memset(TF,0,sizeof(TF));
int ans , k=0 ;
ans = maxFlow_sap(vs , vt , n );
for(int i=0; i<m; i++)
if(edg[i<<1].cap==0)
flag[i]=1;
SF[vs ] =1; bfs(vs , 1);
TF[vt] = 1; bfs(vt , 0);
for(int i=0; i<m; i++)
if(!flag[i]){
v=edg[i<<1|1].to;
u=edg[i<<1].to;
if(SF[u]&&TF[v])
k++;
}
if(k) ans++;
printf("%d %d\n",ans , k);
}
}
|