士兵的旅行 【最大流 建模】

来源:互联网 发布:mac怎么同时开两个窗口 编辑:程序博客网 时间:2024/06/07 21:34

在某个国家有n个城市,他们通过m条无向的道路相连。每个城市有一支军队。第i个城市的军队有ai个士兵。现在士兵开始移动。每个士兵可以呆在原地,或者走到和他所在城市直接相邻的城市,即设每一条边长度为1的话,他离开之后不能距离原来城市大于1。

判断移动之后,能不能使得第i个城市恰好有bi个士兵。

Input
单组测试数据。
第一行有两个整数n和m(1 ≤ n ≤ 100, 0 ≤ m ≤ 200)。
第二行包含n个整数 a1, a2, …, an (0 ≤ ai ≤ 100)。
第三行包含n个整数b1, b2, …, bn (0 ≤ bi ≤ 100)。
接下来m行,每行给出两个整数 p 和q (1 ≤ p, q ≤ n, p ≠ q),表示p和q之间有一条无向的道路。
每两个城市之间最多有一条无向的道路。
Output
如果能够调整成功,输出YES,否则输出NO。
Sample Input
4 4
1 2 6 3
3 5 3 1
1 2
2 3
3 4
4 2
Sample Output
YES

思路 : 像这种的 有多点的开始状态 ,然后又给末时候的状态,最后问能能成功的,就是 常常是最大流问题。。

重点 : 建模
这里写图片描述
代码

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<cmath>#include<queue>#include<stack>#include<map>#include<vector>#include<set>#define CLR(a,b) memset((a),(b),sizeof(a))#define inf 0x3f3f3f3f#define mod 100009#define LL long long#define M  1000#define ll o<<1#define rr o<<1|1#define lson o<<1,l,mid#define rson o<<1|1,mid+1,rusing namespace std;struct Edge {    int from,to,cap,flow,next;}edge[M];int n,m;int head[M],vis[M],dis[M],cur[M],top;   queue<int>Q;void init(){    top=0;    memset(head,-1,sizeof(head));}void addedge(int a,int b,int c){    Edge e={a,b,c,0,head[a]};    edge[top]=e;head[a]=top++;    Edge ee={b,a,0,0,head[b]};    edge[top]=ee;head[b]=top++;}int bfs(int st,int ed){    memset(vis,0,sizeof(vis));    memset(dis,-1,sizeof(dis));    while(!Q.empty()) Q.pop();    vis[st]=1;dis[st]=0;    Q.push(st);int now,nexts;    while(!Q.empty())    {        now=Q.front();Q.pop();        for(int i=head[now];i!=-1;i=edge[i].next)        {            Edge e=edge[i];            if(!vis[e.to]&&e.cap>e.flow)            {                vis[e.to]=1;                dis[e.to]=dis[now]+1;                if(e.to==ed) return 1;                Q.push(e.to);            }        }    }    return 0;}int dfs(int now,int a,int ed){    if(a==0||now==ed) return a;    int flow=0,f;    for(int& i=cur[now];i!=-1;i=edge[i].next)    {        Edge& e=edge[i];        if(dis[e.to]==dis[now]+1&&(f=dfs(e.to,min(a,e.cap-e.flow),ed))>0)        {            e.flow+=f;            edge[i^1].flow-=f;            a-=f;            flow+=f;            if(a==0) break;        }    }    return flow;}int max_flow(int st,int ed){    int flow=0;    while(bfs(st,ed))    {        memcpy(cur,head,sizeof(head));        flow+=dfs(st,inf,ed);     }    return flow;}int main(){    int n,m;    scanf("%d%d",&n,&m);    int st=0;int ed=n<<1|1; //以点0 为源点 ,点2*n+1为汇点     init();    int i,j;int flag;    int sum1,sum2;    sum1=sum2=0;    for(i=1;i<=n;i++)//每个城市的容量 可以当作 源点到其点最大的容量    {    //  添加边顶点的顺序 eg不能addedge (i,st,aa);           int aa;scanf("%d",&aa);        addedge(st,i,aa);//源点与起点连接        addedge(i,i+n,aa);//其点和其镜像点 相连接。这里也可以inf 来填充,边权 。        sum1+=aa;    }    for(i=1+n;i<=n*2;i++)    {        int bb;scanf("%d",&bb);        addedge(i,ed,bb);// 镜像点与汇点相连接        sum2+=bb;    }    while(m--)    {        int a,b,c;        scanf("%d%d",&a,&b);// inf 表明 两城市之间可以 无限交换        addedge(a,b+n,inf);        addedge(b,a+n,inf);    }    if(sum1==sum2&&max_flow(st,ed)==sum1) flag=1; else flag=0;//如果能够 改变成功说明 到达汇点的 最大流一定为 所有的士兵个数    printf("%s\n",flag?"YES":"NO");    return 0;}
0 0
原创粉丝点击