poj1161 walls floyd算法+把面当结点建图
2015-11-09 10:49
796 查看
题意:在一个国家里
所有的城镇被城墙分割
因此国家被分为几个区域
从一个区域到另一个区域必须通过城镇或者穿过城墙
每两个城市之间最多只有一个城墙
这里有一个俱乐部,俱乐部的人住在城镇里
这个城镇最多只有一个人
成员们打算在某个区域里开会
他们不想进入城市
并且他们想爱你个尽量少的穿越城墙
为了开会,每个成员都要穿越一定数量的城墙
他们想要每个人穿越城墙数之和最小
城市被标记为1到n
计算出最有区域和最小交叉和
M个区域 2 200
n歌城市 3 250
l成员数 1 30
每个成员居住的城市
思路:把区域当成结点,当两个区域有公共边的时候,那么久说明这两个区域相邻,既有边。如此建图后跑一次floyd就可以知道任意两个结点的最短路了,然后枚举每个聚会区域,再枚举每个俱乐部点的相邻区域,求每个俱乐部点到聚会区域的最少翻墙数,求得sum,并和ans取min就是ans了。
#include<stdio.h>
#include<string.h>
#include <iostream>
using namespace std;
#define maxn 330
int edge[maxn][maxn];
int markedge[maxn][maxn];
int mapi[maxn][maxn];
int secondv,n,m,clubsum,firstv,sum;
int club[maxn];
#define inf INT_MAX
void floyd()
{
for(int i=0; i<m; i++)
mapi[i][i]=0;
for(int k=0; k<m; k++)
{
for(int i=0; i<m; i++)
{
if(mapi[i][k]!=-1)
{
for(int j=0; j<m; j++)
{
if(mapi[k][j]!=-1)
{
if(mapi[i][j]==-1||mapi[i][j]>mapi[i][k]+mapi[j][k])
{
mapi[i][j]=mapi[i][k]+mapi[k][j];
}
}
}
}
}
}
}
int main()
{
while(~scanf("%d",&m))
{
int tmpv,tmpedge;
scanf("%d%d",&n,&clubsum);
for(int i=0; i<clubsum; i++)
scanf("%d",&club[i]);
memset(mapi,-1,sizeof(mapi));
memset(markedge,0,sizeof(markedge));
memset(edge,-1,sizeof(edge));
for(int i=0; i<m; i++)
{
scanf("%d%d",&sum,&firstv);
markedge[firstv][i]=1;
tmpv=firstv;
for(int j=1; j<sum; j++)
{
scanf("%d",&secondv);
markedge[secondv][i]=1;
tmpedge=edge[tmpv][secondv];
if(tmpedge!=-1)
{
mapi[tmpedge][i]=mapi[i][tmpedge]=1;
}
else
{
edge[tmpv][secondv]=edge[secondv][tmpv]=i;
}
tmpv=secondv;
}
tmpedge=edge[tmpv][firstv];
if(tmpedge!=-1)
{
mapi[tmpedge][i]=mapi[i][tmpedge]=1;
}
else
{
edge[tmpv][firstv]=edge[firstv][tmpv]=i;
}
}
floyd();
int ans=inf;
for(int i=0; i<m; i++)
{
int sum=0;
for(int j=0; j<clubsum; j++)
{
int mm=inf;
for(int k=0; k<m; k++)
{
if(markedge[club[j]][k])
{
mm=min(mm,mapi[k][i]);
}
}
sum+=mm;
}
ans=min(ans,sum);
}
printf("%d\n",ans);
}
}
所有的城镇被城墙分割
因此国家被分为几个区域
从一个区域到另一个区域必须通过城镇或者穿过城墙
每两个城市之间最多只有一个城墙
这里有一个俱乐部,俱乐部的人住在城镇里
这个城镇最多只有一个人
成员们打算在某个区域里开会
他们不想进入城市
并且他们想爱你个尽量少的穿越城墙
为了开会,每个成员都要穿越一定数量的城墙
他们想要每个人穿越城墙数之和最小
城市被标记为1到n
计算出最有区域和最小交叉和
M个区域 2 200
n歌城市 3 250
l成员数 1 30
每个成员居住的城市
思路:把区域当成结点,当两个区域有公共边的时候,那么久说明这两个区域相邻,既有边。如此建图后跑一次floyd就可以知道任意两个结点的最短路了,然后枚举每个聚会区域,再枚举每个俱乐部点的相邻区域,求每个俱乐部点到聚会区域的最少翻墙数,求得sum,并和ans取min就是ans了。
#include<stdio.h>
#include<string.h>
#include <iostream>
using namespace std;
#define maxn 330
int edge[maxn][maxn];
int markedge[maxn][maxn];
int mapi[maxn][maxn];
int secondv,n,m,clubsum,firstv,sum;
int club[maxn];
#define inf INT_MAX
void floyd()
{
for(int i=0; i<m; i++)
mapi[i][i]=0;
for(int k=0; k<m; k++)
{
for(int i=0; i<m; i++)
{
if(mapi[i][k]!=-1)
{
for(int j=0; j<m; j++)
{
if(mapi[k][j]!=-1)
{
if(mapi[i][j]==-1||mapi[i][j]>mapi[i][k]+mapi[j][k])
{
mapi[i][j]=mapi[i][k]+mapi[k][j];
}
}
}
}
}
}
}
int main()
{
while(~scanf("%d",&m))
{
int tmpv,tmpedge;
scanf("%d%d",&n,&clubsum);
for(int i=0; i<clubsum; i++)
scanf("%d",&club[i]);
memset(mapi,-1,sizeof(mapi));
memset(markedge,0,sizeof(markedge));
memset(edge,-1,sizeof(edge));
for(int i=0; i<m; i++)
{
scanf("%d%d",&sum,&firstv);
markedge[firstv][i]=1;
tmpv=firstv;
for(int j=1; j<sum; j++)
{
scanf("%d",&secondv);
markedge[secondv][i]=1;
tmpedge=edge[tmpv][secondv];
if(tmpedge!=-1)
{
mapi[tmpedge][i]=mapi[i][tmpedge]=1;
}
else
{
edge[tmpv][secondv]=edge[secondv][tmpv]=i;
}
tmpv=secondv;
}
tmpedge=edge[tmpv][firstv];
if(tmpedge!=-1)
{
mapi[tmpedge][i]=mapi[i][tmpedge]=1;
}
else
{
edge[tmpv][firstv]=edge[firstv][tmpv]=i;
}
}
floyd();
int ans=inf;
for(int i=0; i<m; i++)
{
int sum=0;
for(int j=0; j<clubsum; j++)
{
int mm=inf;
for(int k=0; k<m; k++)
{
if(markedge[club[j]][k])
{
mm=min(mm,mapi[k][i]);
}
}
sum+=mm;
}
ans=min(ans,sum);
}
printf("%d\n",ans);
}
}
相关文章推荐
- I2C接口
- linux 下eclipse 及c/c++开发环境的搭建:
- [ahk]获取招商证券中的资金
- linux下c/c++实例之七递归扫描目录下的文件
- 新手入门自定义viewGroup
- 如何理解OpenCV与OpenGL的差别
- 2015-11-9 单词记录
- Mutex::AutoLock介绍
- js
- 检测用户是否开启推送
- ubuntu系统 刷bios
- 遍历可变数组的同时删除数组元素的几种解决方案
- Kruskal算法
- 窗口和对话框居中对齐
- 配置tomcat,在访问时不需要加端口号和工程名
- Linux下用makepasswd和passwordmaker生成密码
- oracle定时添加或删除分区表的分区
- 二维码的生成
- LeetCode Plus One
- UnKnownHostException