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
3
0 50 30
50 0 40
30 40 0
Sample Output
90
题意翻译
大学网络由N台计算机组成,系统管理员收集有关节点之间流量的信息,并仔细地将网络划分为两个子网,以最大程度地减少各部分之间的流量。
心怀不满的计算机科学专业学生瓦夏在被大学开除后,决定复仇。他入侵了大学网络,并决定重新分配计算机,以最大化两个子网之间的流量。
不幸的是,他发现计算这种最糟糕的细分是他作为学生未能解决的问题之一。所以他要求你,一个更成功的CS学生,帮助他。
流量数据以矩阵 C 的形式给出,其中 Cij 是第 i 个和第 j 个节点之间发送的数据量(Cij = Cji,Cii = 0)。目标是将网络节点划分为两个不相交的子集 A 和 B,以便最大化总和 ∑Cij (i∈A,j∈B)。
简单来说就是:给出一个n×n的矩阵C,Cij表示第i个点和第j个点的距离,要求将这n个点分为两个集合A和B,求集合A中各点到集合B中各点的距离和的最大值。
题解
关于最大割(无权值)
将图G的顶点集V划分为S和T,目的是使得子集S和子集T之间的边数最大。
注意:
(1)是将V划分为两个非空子集,并且全集V为S和T的并集,S和T无公共顶点
(2)最大割:是要子集S和子集T之间的关联的边数尽可能的大,这个边是图G中真实存在的
注意:如果边带有权重,最大割问题的划分目标就是使得S和T之间关联边的权重之和最大,二者之间的目标函数只是差了个权重系数。
AC代码
#include<cstdio>
using namespace std;
const int N=25;
int a[N][N];
bool vis[N]={0}; //对拿出的节点进行标记
int n,ans=0;
void dfs(int m,int sum){
if(m==n+1){
return; //访问到最后一行返回
}
if(sum>ans){
ans=sum; //修改最大值
}
int t=sum; //记录当前值,返回时使用
vis[m]=1; //标记被拿出的节点
for(int i=1;i<=n;i++){
if(vis[i]==1){
sum-=a[m][i]; //将被拿出的节点所对的减去
}else{
sum+=a[m][i]; //将未被拿出节点加上
}
}
dfs(m+1,sum); //对下一行进行搜索
vis[m]=0; //返回后将标记删除
dfs(m+1,t); //继续搜索下一行
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&a[i][j]);
}
}
dfs(1,0);
printf("%d\n",ans);
return 0;
}