Problem Address:http://poj.org/problem?id=2531
【前言】
不知为何,今晚网速超级无语的慢。
本来还想玩一下游戏,最后只能跑来做道水题。
一开始题意没看清就胡乱写,WA了两次。
然后重新写了。
事实上就是利用DFS生成组合数的问题。
最后还学习了随机算法。
这算是第一次接触随机算法,嗯,效率还不错。
【思路】
题意:
n个结点,两两之间有一个流量。要求把所有点分成两堆,使得两堆之间的流量最大。
DFS:
枚举分成1...m(m=n/2)堆,利用dfs生成C(n,1)、C(n,2)...C(n,m),并计算组合内两堆之间的流量和,最后记录其最大值者。
因为2<=n<=20,所以暴力完全可以接受。
随机算法:
假设开始的时候全部只有一堆。每次改变其中的某个结点,将其放到相反的另一堆中,同时计算流量和。
多次改变随机结点的状态,最后记录其最大值者。
n*5000次运算即可得到答案。
【代码】
代码没有优化,时间在300ms左右。完全可以剪枝以及优化。
DFS:
#include <iostream>
using namespace std;
const int maxn = 20;
bool visited[maxn+5];
int map[maxn+5][maxn+5];
int max_sum;
int l[maxn+5], r[maxn+5];
int n;
void dfs(int nv, int p, int lct)
{
int i, j;
int temp;
if (lct==nv)
{
int rct = 0;
for(i=0; i<n; i++)
{
if (!visited[i])
{
r[rct] = i;
rct++;
}
}
temp = 0;
for (i=0; i<lct; i++)
{
for (j=0; j<rct; j++)
{
temp += map[l[i]][r[j]];
}
}
if (temp>max_sum)
max_sum = temp;
}
else
{
for (i=p; i<n; i++)
{
if(!visited[i])
{
l[lct] = i;
visited[i] = true;
dfs(nv, i+1, lct+1);
visited[i] = false;
}
}
}
}
int main()
{
int mid;
int i, j;
scanf("%d", &n);
for (i=0; i<n; i++)
{
for (j=0; j<n; j++)
scanf("%d", &map[i][j]);
}
max_sum = -INT_MAX;
mid = n/2;
for (i=1; i<=mid; i++)
{
memset(visited, false, sizeof(visited));
dfs(i, 0, 0);
}
printf("%d\n", max_sum);
return 0;
}
随机算法:
#include <iostream>
using namespace std;
const int maxn = 20;
int re[maxn+5];
int map[maxn+5][maxn+5];
int max_sum;
int n;
int solve()
{
int i, j;
int temp = 0;
i = rand()%n;
re[i] = 1 - re[i];
for (i=0; i<n; i++)
{
if (re[i]==1)
{
for (j=0; j<n; j++)
{
if (re[j]==0)
temp += map[i][j];
}
}
}
return temp;
}
int main()
{
int i, j;
int temp;
scanf("%d", &n);
for (i=0; i<n; i++)
{
for (j=0; j<n; j++)
scanf("%d", &map[i][j]);
}
max_sum = -INT_MAX;
memset(re, 0, sizeof(re));
int time = n*5000;
while(time--)
{
temp = solve();
if (temp>max_sum)
max_sum = temp;
}
printf("%d\n", max_sum);
return 0;
}