UVALive 7303 Aquarium 最小生成树
2017-04-30 09:58
316 查看
题意:给定一个n*m的方格,每个方格都由'/'或'\'来分隔成两个部分,假设他们是一堵墙,有它的坚硬程度,
现在需要打破其中一些墙,来使得每个格子都连通,并且所需的坚硬值最小。
思路:连通性问题并要求权值最小,那就是最小生成树的问题了,建图,因为每个格子都分隔成两个部分,所以
所以给这两个部分编号,墙壁的坚硬值就是连接这两部分的权值,再分类讨论一下,这两部分与其周围相邻
部分的联通情况,权值为0,仔细考虑就不会写错,为了方便表示,规定每个格子的上半部分比下半部分的编
号小1,最后来一遍最小生成树就可以了。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <set>
#include <queue>
using namespace std;
const int INF=1e9+10;
const double EPS = 1e-10;
typedef long long ll;
int v[105][105],cnt[105][105];
char mp[105][105];
struct edge{
int u,v,cost;
};
bool cmp(edge a,edge b){
return a.cost<b.cost;
}
edge es[100000];
int par[200050];
void init(int n){
for(int i=0;i<=n;i++){
par[i]=i;
}
}
int find(int x){
if(par[x]==x)
return x;
else
return par[x]=find(par[x]);
}
void unite(int x,int y){
x=find(x);
y=find(y);
if(x!=y)
par[x]=y;
}
bool same(int x,int y){
return find(x)==find(y);
}
ll solve(int n,int k){
init(n);
ll res=0;
sort(es,es+k,cmp);
for(int i=0;i<k;i++){
edge e=es[i];
if(!same(e.u,e.v)){
unite(e.u,e.v);
res+=1LL*e.cost;
}
}
return res;
}
int main(){
//freopen("out.txt","w",stdout);
int t;
scanf("%d",&t);
int cas=1;
while(t--){
int n,m;
scanf("%d %d",&n,&m);
for(int i=0;i<n;i++){
scanf("%s",mp[i]);
}
int k=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
scanf("%d",&v[i][j]);
cnt[i][j]=k;
k+=2;
}
int mxnode=k-1;
k=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
int a=cnt[i][j];
int b=a+1;
es[k++]=(edge){a,b,v[i][j]};
if(mp[i][j]=='/'){
int x1=i-1,y1=j-1;
if(x1>=0){
es[k++]=(edge){a,cnt[x1][j]+1,0};
}
if(y1>=0){
if(mp[i][y1]=='/')
es[k++]=(edge){a,cnt[i][y1]+1,0};
else
es[k++]=(edge){a,cnt[i][y1],0};
}
x1=i+1,y1=j+1;
if(x1<n){
es[k++]=(edge){b,cnt[x1][j],0};
}
if(y1<m){
if(mp[i][y1]=='/')
es[k++]=(edge){b,cnt[i][y1],0};
else
es[k++]=(edge){b,cnt[i][y1]+1,0};
}
}
else{
int x1=i-1,y1=j+1;
if(x1>=0){
es[k++]=(edge){a,cnt[x1][j]+1,0};
}
if(y1<m){
if(mp[i][y1]=='/')
es[k++]=(edge){a,cnt[i][y1],0};
else
es[k++]=(edge){a,cnt[i][y1]+1,0};
}
x1=i+1,y1=j-1;
if(x1<n){
es[k++]=(edge){b,cnt[x1][j],0};
}
if(y1>=0){
if(mp[i][y1]=='/')
es[k++]=(edge){b,cnt[i][y1]+1,0};
else
es[k++]=(edge){b,cnt[i][y1],0};
}
}
}
}
ll ans=solve(mxnode,k);
//printf("Case %d: %lld\n",cas++,ans );
cout<<"Case "<<cas++<<": "<<ans<<endl;
}
return 0;
}
现在需要打破其中一些墙,来使得每个格子都连通,并且所需的坚硬值最小。
思路:连通性问题并要求权值最小,那就是最小生成树的问题了,建图,因为每个格子都分隔成两个部分,所以
所以给这两个部分编号,墙壁的坚硬值就是连接这两部分的权值,再分类讨论一下,这两部分与其周围相邻
部分的联通情况,权值为0,仔细考虑就不会写错,为了方便表示,规定每个格子的上半部分比下半部分的编
号小1,最后来一遍最小生成树就可以了。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <set>
#include <queue>
using namespace std;
const int INF=1e9+10;
const double EPS = 1e-10;
typedef long long ll;
int v[105][105],cnt[105][105];
char mp[105][105];
struct edge{
int u,v,cost;
};
bool cmp(edge a,edge b){
return a.cost<b.cost;
}
edge es[100000];
int par[200050];
void init(int n){
for(int i=0;i<=n;i++){
par[i]=i;
}
}
int find(int x){
if(par[x]==x)
return x;
else
return par[x]=find(par[x]);
}
void unite(int x,int y){
x=find(x);
y=find(y);
if(x!=y)
par[x]=y;
}
bool same(int x,int y){
return find(x)==find(y);
}
ll solve(int n,int k){
init(n);
ll res=0;
sort(es,es+k,cmp);
for(int i=0;i<k;i++){
edge e=es[i];
if(!same(e.u,e.v)){
unite(e.u,e.v);
res+=1LL*e.cost;
}
}
return res;
}
int main(){
//freopen("out.txt","w",stdout);
int t;
scanf("%d",&t);
int cas=1;
while(t--){
int n,m;
scanf("%d %d",&n,&m);
for(int i=0;i<n;i++){
scanf("%s",mp[i]);
}
int k=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
scanf("%d",&v[i][j]);
cnt[i][j]=k;
k+=2;
}
int mxnode=k-1;
k=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
int a=cnt[i][j];
int b=a+1;
es[k++]=(edge){a,b,v[i][j]};
if(mp[i][j]=='/'){
int x1=i-1,y1=j-1;
if(x1>=0){
es[k++]=(edge){a,cnt[x1][j]+1,0};
}
if(y1>=0){
if(mp[i][y1]=='/')
es[k++]=(edge){a,cnt[i][y1]+1,0};
else
es[k++]=(edge){a,cnt[i][y1],0};
}
x1=i+1,y1=j+1;
if(x1<n){
es[k++]=(edge){b,cnt[x1][j],0};
}
if(y1<m){
if(mp[i][y1]=='/')
es[k++]=(edge){b,cnt[i][y1],0};
else
es[k++]=(edge){b,cnt[i][y1]+1,0};
}
}
else{
int x1=i-1,y1=j+1;
if(x1>=0){
es[k++]=(edge){a,cnt[x1][j]+1,0};
}
if(y1<m){
if(mp[i][y1]=='/')
es[k++]=(edge){a,cnt[i][y1],0};
else
es[k++]=(edge){a,cnt[i][y1]+1,0};
}
x1=i+1,y1=j-1;
if(x1<n){
es[k++]=(edge){b,cnt[x1][j],0};
}
if(y1>=0){
if(mp[i][y1]=='/')
es[k++]=(edge){b,cnt[i][y1]+1,0};
else
es[k++]=(edge){b,cnt[i][y1],0};
}
}
}
}
ll ans=solve(mxnode,k);
//printf("Case %d: %lld\n",cas++,ans );
cout<<"Case "<<cas++<<": "<<ans<<endl;
}
return 0;
}
相关文章推荐
- UVALive-7303- Aquarium【最小生成树】【连通块】
- UVALive-7303 Aquarium (最小生成树)
- UVALive 3662 Another Minimum Spanning Tree 曼哈顿最小生成树
- UVALive 3662 Another Minimum Spanning Tree [离散化+线段树+最小生成树]
- UVALive 6437 Power Plant 【最小生成树 + 思维】
- 曼哈顿最小距离生成树(poj 3241&& UVALive 3662)
- UVALive 3662 Another Minimum Spanning Tree 曼哈顿最小距离生成树
- UVALive 3887 边权极差最小生成树模板
- UVALive - 4872 最小生成树
- UVAlive 3662 Another Minimum Spanning Tree 莫队算法,曼哈顿最小生成树
- UVA Live 6437 Power Plant 最小生成树
- 【UVALive】3887 Slim Span 枚举+最小生成树
- UVALive - 4848 Tour Belt(暴力+最小生成树)
- UVALive 4872 Underground Cables 最小生成树
- B - Bus Problem UVALive - 7001 最小生成树
- UVALive - 5713 最小生成树
- 最小生成树应用uvalive5713
- UVA Live 6437 Power Plant 最小生成树
- UVALive 6837 (最小生成树)
- Another Minimum Spanning Tree - UVaLive 3662 曼哈顿最小生成树