poj 2531 Network Saboteur

来源:互联网 发布:苹果淘宝旗舰店是官方 编辑:程序博客网 时间:2024/05/01 20:06
Network Saboteur
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 8822 Accepted: 4106

Description

A university network is composed of N computers. System administrators gathered information on the traffic between nodes, and carefully divided the network into two subnetworks in order to minimize traffic between parts. 
A disgruntled computer science student Vasya, after being expelled from the university, decided to have his revenge. He hacked into the university network and decided to reassign computers to maximize the traffic between two subnetworks. 
Unfortunately, he found that calculating such worst subdivision is one of those problems he, being a student, failed to solve. So he asks you, a more successful CS student, to help him. 
The traffic data are given in the form of matrix C, where Cij is the amount of data sent between ith and jth nodes (Cij = Cji, Cii = 0). The goal is to divide the network nodes into the two disjointed subsets A and B so as to maximize the sum ∑Cij (i∈A,j∈B).

Input

The first line of input contains a number of nodes N (2 <= N <= 20). The following N lines, containing N space-separated integers each, represent the traffic matrix C (0 <= Cij <= 10000). 
Output file must contain a single integer -- the maximum traffic between the subnetworks. 

Output

Output must contain a single integer -- the maximum traffic between the subnetworks.

Sample Input

30 50 3050 0 4030 40 0

Sample Output

90


大致题意:给你一个无向图,将这个图分成两个子图,每个子图内部通信不花费,两个子图通信花费,

        如何分配两个子图,使得通信花费最大,比如(1,2) (3), 那么通信花费就是

        cost[1][3] + cost[2][3].

解题思路:(dfs)因为给出的数据只有20,可以采用暴力枚举,就是枚举一个集合包含的元素,找出所有情况

        最大的花费,有两种枚举方法,一种耗时很大,一种是剪枝。

        第一种:每一次加入新的节点,就重新计算花费。

        第二种:每一次加入新的节点,根据以前的花费计算当前花费,如果花费没有增大,就没必要

               枚举其他情况。


第一种:

#include <stdio.h>#include <string.h>int map[21][21];char vis[21];int n, ans;void dfs(int cur){     vis[cur] = 1;     int cost = 0;     for (int i=0; i<n; ++i)       // 重新计算花费     {         for (int j=0; j<n; ++j)             if (vis[i]&& !vis[j])                cost += map[i][j];     }          if (cost > ans)        ans = cost;     for (int i=cur+1; i<n; ++i)     {         dfs(i);         vis[i] = 0;     }}int main(){    while (~scanf("%d", &n))    {               for (int i=0; i<n; ++i)              for (int j=0; j<n; ++j)              scanf("%d", &map[i][j]);          memset(vis, 0, sizeof(vis));          ans = 0;          dfs(0);          printf("%d\n", ans);    }        return 0;}

第二种:

#include <stdio.h>#include <string.h>int map[21][21];char vis[21];int n, ans;void dfs(int cur, int cost){     vis[cur] = 1;     int tmp = cost;     for (int i=0; i<n; ++i)     {         if (!vis[i])            tmp += map[cur][i];     // 不在同一集合就要加上花费          else             tmp -= map[cur][i];    // 以前i与cur不在同一集合的时候,加上了map[cur][i]                                    // 现在在同一集合了,就要减去。      }          if (tmp > ans)  // 更新最大值         ans = tmp;     if (tmp > cost) // 如果集合加入cur并没有增大花费,就没必要枚举其他的(剪枝)      for (int i=cur+1; i<n; ++i) // 枚举      {         dfs(i, tmp);         vis[i] = 0; //回溯      }}int main(){    while (~scanf("%d", &n))    {               for (int i=0; i<n; ++i)              for (int j=0; j<n; ++j)              scanf("%d", &map[i][j]);          memset(vis, 0, sizeof(vis));          ans = 0;          dfs(0, 0);          printf("%d\n", ans);    }        return 0;}



0 0
原创粉丝点击