`
kmplayer
  • 浏览: 512613 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

国际大学生程序设计竞赛例题_5.3狙击兵

J# 
阅读更多
1,起点:0,终点:n
1到n-1设置n-1的狙击点,给定边和每个点至少需要的狙击兵数量.
求:成功阻击最少需要多少个狙击手?
2,解答:
最大流最小割定理.
这里需要将一个点拆成一条边.
举例:

相应的生成图为:



3,实例代码:
#include <iostream>
#include <queue>
using namespace std;

const int maxN=105;
const int inf=0xffff;

bool g[maxN][maxN];//关系数组,初始图
int edge[maxN][maxN];//生成图的邻接权矩阵

int n,m;//顶点数和边数
int cnt;//测试数目
int ans;

bool visited[maxN];
int father[maxN];

void Ford_Fulkerson()
{
    while(1)
    {
        //一次大循环,找到一条可能的增广路径
        queue <int> q;
        memset(visited, 0, sizeof(visited));
        memset(father, -1, sizeof(father));
        int now;
        visited[0] = true;
        q.push(0);
        while(!q.empty())//广度优先
        {
            now = q.front();
            q.pop();
            if(now == n-1) break;
            for(int i=0; i<n+n-2; i++) //生成图定点数
            {
                //每次父亲节点都要更新,权值减为0的边就不算了.
                if(edge[now][i] && !visited[i])
                {
                    father[i] = now;
                    visited[i] = true;
                    q.push(i);
                }
            }
        }
        //可能的增广路不存在了
        if(!visited[n-1]) break; //终点标号
        int u, min = inf;
        for(u=n-1; u; u=father[u])//找出权值最小的边
        {
            if(edge[father[u]][u] < min)
                min = edge[father[u]][u];
        }
        //减去最小权值
        for(u=n-1; u; u=father[u])
        {
            //前向弧减去
            edge[father[u]][u] -= min;
            //后向弧加上
            //存在圆环,这句话关键
            edge[u][father[u]] += min;
        }
        //当前增广路径增加的流
        ans+=min;
    }
}

int main()
{
    freopen("5.3.in","r",stdin);
    cin>>cnt;
    int s,e,temp;
    while(cnt--)
    {
        ans=0;
        memset(g,0,sizeof(g));
        memset(edge,0,sizeof(edge));
        cin>>n>>m;
        n+=1;
        for(int i=1;i<=n-2;i++)
        {
            int num;//狙击兵个数
            cin>>num;
            //将点分成一条边
            edge[i][i+n-1]=num;
        }
        for(int i=0;i<m;i++)
        {
            cin>>s>>e;
            if(s>e)
            {
                temp=s;
                s=e;
                e=temp;
            }
            g[s][e]=true;
            if(s!=0&&e!=n-1) //不含有起点或终点,设定为双向边
                g[e][s]=true;
        }

        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
            {
                if(g[i][j])
                {
                    if(i==0) edge[i][j]=inf;
                    if(i!=0) edge[i+n-1][j]=inf;
                }
            }
        Ford_Fulkerson();
        cout<<ans<<endl;
    }
    return 0;
}
  • 大小: 679 Bytes
  • 大小: 1.1 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics