1.A - 畅通工程 HDU - 1863
板子题
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
int n,m;
int arc[110][110],flag[110],dist[110];
void prim()
{
dist[1]=0;
int ans=0;
for(int i=1;i<=m;i++)
{
int k=-1;
for(int j=1;j<=m;j++)
{
if(!flag[j]&&(k==-1||dist[k]>dist[j]))k=j;
}
if(dist[k]==INF)
{
printf("?\n");
return ;
}
flag[k]=1;
ans+=dist[k];
for(int j=1;j<=m;j++)dist[j]=min(dist[j],arc[k][j]);
}
printf("%d\n",ans);
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
if(n==0)break;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=m;j++)
{
if(i==j)arc[i][j]=0;
else arc[i][j]=INF;
}
}
memset(flag,0,sizeof(flag));
memset(dist,INF,sizeof(dist));
while(n--)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(z<arc[x][y])arc[x][y]=arc[y][x]=z;
}
prim();
}
return 0;
}
POJ这题数据好水,刚开始写错了,没有并查集查找就可以过。
int n,m;
struct node
{
int x,y,z;
}w[5000];
int fa[110];
bool cmp(node a,node b){return a.z<b.z;}
int check(int x)
{
return x==fa[x]?x:fa[x]=check(fa[x]);
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
if(n==0)break;
for(int i=1;i<=n;i++)scanf("%d%d%d",&w[i].x,&w[i].y,&w[i].z);
for(int i=1;i<=m;i++)fa[i]=i;
sort(w+1,w+1+m,cmp);
int ans=0;
for(int i=1;i<=m;i++)
{
int x=w[i].x;
int y=w[i].y;
if(check(x)==check(y))continue;
fa[y]=x;
ans+=w[i].z;
}
int k=0;
for(int i=1;i<=m;i++){if(fa[i]==i)k++;}
if(k>1)printf("?\n");
else printf("%d\n",ans);
}
return 0;
}
2.Truck History POJ - 1789
刚开始挺懵逼,这玩意是在干嘛。
思路:把两个字符串相同位置不同字母的个数作为距离,求最小生成树。(原来就是这么个玩意)剩下就是板子了。
做了几道题了总感觉prim比较好用
using namespace std;
char s[2010][10];
int mp[2010][2010],dist[2010],vis[2010];
int n;
void prim()
{
memset(dist,INF,sizeof(dist));
memset(vis,0,sizeof(vis));
dist[0]=0;
int ans=0;
for(int i=0;i<n;i++)
{
int k=-1;
for(int j=0;j<n;j++)
{
if(!vis[j]&&(k==-1||dist[k]>dist[j]))k=j;
}
ans+=dist[k];
vis[k]=1;
for(int j=0;j<n;j++)dist[j]=min(dist[j],mp[k][j]);
}
printf("The highest possible quality is 1/%d.\n",ans);
}
int main()
{
while(~scanf("%d",&n)&&n)
{
for(int i=0;i<n;i++)scanf("%s",s[i]);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
int k=0;
for(int z=0;z<7;z++)
{
if(s[i][z]!=s[j][z])k++;
}
mp[i][j]=mp[j][i]=k;
}
}
prim();
}
return 0;
}
题目:Arctic Network POJ - 2349
本来想的有点复杂,后来发现只要求出最小生成树,然把dist从大到小排序,输出第s个就好,注意是第s个,刚开始以为是s+1;
int t,n,m;
double mp[510][510],dist[510];
int vis[510];
struct node
{
int x,y;
}w[510];
bool cmp(double x,double y){return x>y;}
void prim()
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)dist[i]=mp[1][i];
for(int i=1;i<=n;i++)
{
int k=-1;
for(int j=1;j<=n;j++)
{
if(!vis[j]&&(k==-1||dist[k]>dist[j]))k=j;
}
vis[k]=1;
for(int j=1;j<=n;j++)
{
if(!vis[j])dist[j]=min(dist[j],mp[k][j]);
}
}
sort(dist+1,dist+1+n,cmp);
printf("%.2lf\n",dist[m]);
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++)scanf("%d%d",&w[i].x,&w[i].y);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
mp[i][j]=mp[j][i]=sqrt((double)((w[i].x-w[j].x)*(w[i].x-w[j].x)+(w[i].y-w[j].y)*(w[i].y-w[j].y)));
}
}
prim();
}
return 0;
}
4.Highways POJ - 1751
真的是很简单的一个题,好多次超时整得我一脸懵逼,原来把多组输入改掉就好,什么鬼。
思路:求最小生成树,加个数组p[]保存dist的另一点就好,然后dist不为零,输出i,p[i]就好。
int n,m;
double mp[760][760],dist[760];
int vis[760],p[760];
struct node
{
int x,y;
}w[760];
void prim()
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)dist[i]=mp[1][i],p[i]=1;
for(int i=1;i<=n;i++)
{
int k=-1;
for(int j=1;j<=n;j++)
{
if(!vis[j]&&(k==-1||dist[k]>dist[j]))k=j;
}
vis[k]=1;
for(int j=1;j<=n;j++)
{
if(!vis[j]&&mp[k][j]<dist[j])
{
dist[j]=mp[k][j];
p[j]=k;
}
}
}
for(int i=1;i<=n;i++)
{
if(dist[i])
{
printf("%d %d\n",i,p[i]);
}
}
}
inline double add(int x1,int y1,int x2,int y2)
{
return sqrt((double)((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)));
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d%d",&w[i].x,&w[i].y);
for(int i=1;i<=n;i++)
{
for(int j=1;j<i;j++)
{
mp[i][j]=mp[j][i]=add(w[i].x,w[i].y,w[j].x,w[j].y);
}
mp[i][i]=0;
}
scanf("%d",&m);
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
mp[x][y]=mp[y][x]=0;
}
prim();
return 0;
}
5.题目:The Unique MST POJ - 1679
题意:求最小生成树是否唯一
思路:先Kruskal求出最小生成树,并对边进行标记。然后进行n-1次循环每次删一条已标记边(删完恢复,每次只有一条边被删),然后再次运用Kruskal求最小生成树,结果一样就判断是否能够构成联通图(就是只有一个fa[i]=i),是的话就不唯一跳出,不是就继续。
代码写得好丑,被卡思路了,一直在纠结为什么删一条,万一存在替换一边不行替换多边可以怎么办,后来发现自己就是个傻子,是从总边里删一条,那就删多条存在,删一条一定存在啊,日常犯傻。
int t,n,m;
struct edge
{
int a,b,c,d;
}w[100000];
int fa[110];
int v[110];
bool cmp(edge x,edge y){return x.c<y.c;}
int get(int x){return x==fa[x]?x:fa[x]=get(fa[x]);}
int K()
{
int ans=0;
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++)
{
int x=get(w[i].a);
int y=get(w[i].b);
if(x==y)continue;
ans+=w[i].c;
fa[y]=x;
w[i].d=1;
}
return ans;
}
int K2()
{
int ans=0;
for(int i=1;i<=n;i++)fa[i]=i;
int flag=0;
for(int i=1;i<=m;i++)
{
if(w[i].d==1&&flag==0){flag=1;w[i].d=0;continue;}
int x=get(w[i].a);
int y=get(w[i].b);
if(x==y)continue;
ans+=w[i].c;
fa[y]=x;
}
return ans;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&w[i].a,&w[i].b,&w[i].c);
w[i].d=0;
}
sort(w+1,w+1+m,cmp);
int ans=K();
int ff=0;
for(int i=1;i<=n-1;i++)
{
int ans2=K2();
if(ans2==ans)
{
int k=0;
for(int i=1;i<=n;i++)
{
if(fa[i]==i)k++;
}
if(k==1)
{
ff=1;
break;
}
}
}
if(ff==0)printf("%d\n",ans);
else printf("Not Unique!\n");
}
return 0;
}
6.题目:Borg Maze POJ - 3026
www 这题好恶心,看了好多代码还是决定自己写,求距离BFS和求二叉树有多少层BFS很像,在这里感谢老师学数据结构时老师对我们的“刁难”。
题意:其实就是求S,A(SA等价)构成的最小生成树,不过只能上下左右不能斜着。
思路:先对所有的S,A进行编号,然后根据BFS求出任意两点间的距离,最后prim。思路听起来好简单,代码写了好久,POJ好坑,一些注意的点吧。
1)m,n之后要一定要gets(),否则会wa。2)数组要开大,要不还会wa。3)计算距离要注意,反正我刚开始是在这里出错了。
int t,m,n;
char s[110][110];
int num[110][110](编号),mp[2555][2555](距离);
int dist[2555](prim距离),vis[2555](prim标记);
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
typedef pair<int,int>PII;
int flag[110][110](求距离标记);
void bfs(int xx,int yy,int zz)
{
memset(flag,0,sizeof(flag));
queue<PII>que;
queue<PII>que2;
que.push(PII(xx,yy));
flag[xx][yy]=1;
int vv=1;
while(!que.empty()||!que2.empty())
{
PII pp=que.front();
que.pop();
for(int i=0;i<4;i++)
{
int x=pp.first+dx[i];
int y=pp.second+dy[i];
if(x>n||y>n||x<1||y<1)continue;
else if(s[x][y]=='#')continue;
else if(s[x][y]==' '&&flag[x][y]==0)que2.push(PII(x,y)),flag[x][y]=1;
else if(num[x][y]!=0&&flag[x][y]==0)
{
mp[zz][num[x][y]]=mp[num[x][y]][zz]=vv;
que2.push(PII(x,y));flag[x][y]=1;
}
}
if(que.empty())
{
vv++;
while(!que2.empty())
{
que.push(que2.front());
que2.pop();
}
}
}
}
void prim(int cnt)
{
memset(vis,0,sizeof(vis));
memset(dist,INF,sizeof(dist));
dist[1]=0;
int ans=0;
for(int i=1;i<=cnt;i++)
{
int k=-1;
for(int j=1;j<=cnt;j++)
{
if(!vis[j]&&(k==-1||dist[k]>dist[j]))k=j;
}
vis[k]=1;
ans+=dist[k];
for(int j=1;j<=cnt;j++)dist[j]=min(dist[j],mp[k][j]);
}
printf("%d\n",ans);
}
char c[30];//gets()时用
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&m,&n);
gets(c);
int cnt=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%c",&s[i][j]);
if(s[i][j]=='A'||s[i][j]=='S')num[i][j]=++cnt;
else num[i][j]=0;
}
if(i<n)scanf("%*c");
}
for(int i=1;i<=cnt;i++)
{
for(int j=1;j<=cnt;j++)
{
if(i==j)mp[i][j]=0;
else mp[i][j]=INF;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(num[i][j])bfs(i,j,num[i][j]);
}
}
prim(cnt);
}
return 0;
}
专题终于写完了,虽然除了个别题其他都是水题,但还是很开心。ps:灰色无法在这里提交,已在原网站提交。