今天继续做图论的题
先搞了一题最小生成树模版题
LUOGU3366 【模板】最小生成树
题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz
模版的PRIM ,一开始失了智 没看PPT的程序写了一个类似于bellman-ford的程序 搜索的时候超时了、、后来看了PPT发现好简单,一开始搜索的时候累赘了、每次都从头搜了自然gg附上傻子代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,t,dis[6000],link[6000],ans;
bool flag[6000];
struct bian
{
int sum,n,v;
}bi[500000];
inline void init()
{
scanf("%d%d",&n,&m);
int xx,yy,zz;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&xx,&yy,&zz);
bi[++t].n=link[xx];
bi[t].sum=yy;
bi[t].v=zz;
link[xx]=t;
bi[++t].n=link[yy];
bi[t].sum=xx;
bi[t].v=zz;
link[yy]=t;
}
return;
}
inline void work()
{
memset(flag,0,sizeof(flag));
memset(dis,10,sizeof(dis));
dis[1]=0;
flag[1]=1;
for(int i=1;i<=n-1;i++)
{
for(int q=1;q<=n;q++)
if(flag[q])
for(int j=link[q];j;j=bi[j].n)
{
if(bi[j].v<dis[bi[j].sum])
dis[bi[j].sum]=bi[j].v;
}
int k=0,min=168430090;
for(int j=1;j<=n;j++)
if(!flag[j])
if(min>dis[j])
min=dis[j],k=j;
if(k==0)
{
printf("orz");
break;
}
ans+=min;
flag[k]=true;
}
printf("%d",ans);
return;
}
int main()
{
init();
work();
return 0;
}
下面是看了PPT思路之后写的代码
#include<bits/stdc++.h>
using namespace std;
int n,m,t,dis[6000],link[6000],ans;
bool flag[6000];
struct bian
{
int sum,n,v;
}bi[500000];
inline void init()
{
scanf("%d%d",&n,&m);
int xx,yy,zz;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&xx,&yy,&zz);
bi[++t].n=link[xx];
bi[t].sum=yy;
bi[t].v=zz;
link[xx]=t;
bi[++t].n=link[yy];
bi[t].sum=xx;
bi[t].v=zz;
link[yy]=t;
}
return;
}
inline void work()
{
memset(dis,10,sizeof(dis));
memset(flag,0,sizeof(flag));
dis[1]=0;
for(int i=1;i<=n;i++)
{
int min=168430090,k=0;
for(int j=1;j<=n;j++)
if((!flag[j])&&(dis[j]<min)) min=dis[j],k=j;
flag[k]=true;
for(int j=link[k];j;j=bi[j].n)
if((!flag[bi[j].sum])&&(bi[j].v<dis[bi[j].sum]))
dis[bi[j].sum]=bi[j].v;
if(k==0)
{
printf("orz");
exit(0);
}
ans+=min;
}
printf("%d",ans);
return;
}
int main()
{
init();
work();
return 0;
}
AC完这道题就去做前几天学的图论算法 什么floyd、迪杰斯特拉等等留下的题目了
LUOGU2835 刻录光盘
题目描述在JSOI2005夏令营快要结束的时候,很多营员提出来要把整个夏令营期间的资料刻录成一张光盘给大家,以便大家回去后继续学习。组委会觉得这个主意不错!可是组委会一时没有足够的空光盘,没法保证每个人都能拿到刻录上资料的光盘,又来不及去买了,怎么办呢?!组委会把这个难题交给了LHC,LHC分析了一下所有营员的地域关系,发现有些营员是一个城市的,其实他们只需要一张就可以了,因为一个人拿到光盘后,其他人可以带着U盘之类的东西去拷贝啊!可是,LHC调查后发现,由于种种原因,有些营员并不是那么的合作,他们愿意某一些人到他那儿拷贝资料,当然也可能不愿意让另外一些人到他那儿拷贝资料,这与我们JSOI宣扬的团队合作精神格格不入!!!现在假设总共有N个营员(2<=N<=200),每个营员的编号为1~N。LHC给每个人发了一张调查表,让每个营员填上自己愿意让哪些人到他那儿拷贝资料。当然,如果A愿意把资料拷贝给B,而B又愿意把资料拷贝给C,则一旦A获得了资料,则B,C都会获得资料。现在,请你编写一个程序,根据回收上来的调查表,帮助LHC计算出组委会至少要刻录多少张光盘,才能保证所有营员回去后都能得到夏令营资料?
这题用floyd做,我一开始的思路是floyd排序后 把1能到的点全部标记,然后在找下一个未标记的点,把这个点能到的点再次标记、知道没有未标记的点,输出找到未标记点的次数。代码如下:#include<bits/stdc++.h>
using namespace std;
int n;
bool f[300][300],flag[300];
inline void init()
{
memset(f,0,sizeof(f));
scanf("%d",&n);
int xx;
for(int i=1;i<=n;i++)
while(i<=n)
{
scanf("%d",&xx);
if(xx==0) break;
else f[i][xx]=f[xx][i]=1;
}
return;
}
inline void floyd()
{
for(int i=1;i<=n;i++)
f[i][i]=true;
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]==f[i][j]||(f[i][k]&&f[k][j]);
return;
}
inline void work()
{
memset(flag,0,sizeof(flag));
for(int i=1;i<=n;i++)
if(f[1][i]) flag[i]=true;
int sum=1;
bool check=false;
while(!check)
{
int k=0;
for(int i=1;i<=n;i++)
if(!flag[i]) {k=i;break;}
if(k==0)
break;
sum++;
for(int i=1;i<=n;i++)
if(f[k][i]&&!flag[i]) flag[i]=true;
}
printf("%d",sum);
return;
}
int main()
{
init();
floyd();
work();
return 0;
}
然后悲惨的只有20分、、 后来发现了一个问题 下一个未标记的点并不一定是一条完整传递链的开头 于是加了一段循环 找到这个传递链最开头的那个点。这边要特判防止环死循环 while(!hehe)
{
hehe=true;
int biaoji=k;
for(int i=1;i<=n;i++)
if ((f[i][k])&&(k!=i)) k=i,hehe=false;
if(k==biaoji) {k=biaoji;hehe=true;}
}
从这个bool类型的名字就知道我的心情了= =因为还是WA9个点、、n多分钟后我突然意识到 1并不一定是第一条链的起点、、、改了一下就AC了
#include<bits/stdc++.h>
using namespace std;
int n;
bool f[300][300],flag[300];
inline void init()
{
memset(f,0,sizeof(f));
scanf("%d",&n);
int xx;
for(int i=1;i<=n;i++)
while(i<=n)
{
scanf("%d",&xx);
if(xx==0) break;
else f[i][xx]=f[xx][i]=1;
}
return;
}
inline void floyd()
{
for(int i=1;i<=n;i++)
f[i][i]=true;
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]==f[i][j]||(f[i][k]&&f[k][j]);
return;
}
inline void work()
{
memset(flag,0,sizeof(flag));
for(int i=1;i<=n;i++)
if(f[1][i]) flag[i]=true;
int sum=1;
bool check=false;
while(!check)
{
int k=0;
for(int i=1;i<=n;i++)
if(!flag[i]) {k=i;break;}
if(k==0)
break;
sum++;
for(int i=1;i<=n;i++)
if(f[k][i]&&!flag[i]) flag[i]=true;
}
printf("%d",sum);
return;
}
int main()
{
init();
floyd();
work();
return 0;
}
while(!hehe)
{
hehe=true;
int biaoji=k;
for(int i=1;i<=n;i++)
if ((f[i][k])&&(k!=i)) k=i,hehe=false;
if(k==biaoji) {k=biaoji;hehe=true;}
}
最后AC代码:
#include<bits/stdc++.h>
using namespace std;
int n;
bool f[300][300],flag[300];
inline void init()
{
memset(f,0,sizeof(f));
scanf("%d",&n);
int xx;
for(int i=1;i<=n;i++)
while(i<=n)
{
scanf("%d",&xx);
if(xx==0) break;
else f[i][xx]=true;
}
return;
}
inline void floyd()
{
for(int i=1;i<=n;i++)
f[i][i]=true;
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=f[i][j]||(f[i][k]&&f[k][j]);
return;
}
inline void work()
{
memset(flag,0,sizeof(flag));
int sum=0;
bool check=false;
while(!check)
{
int k=0;
for(int i=1;i<=n;i++)
if(!flag[i]) {k=i;break;}
if(k==0) break;
sum++;
bool hehe=false;
while(!hehe)
{
hehe=true;
int biaoji=k;
for(int i=1;i<=n;i++)
if ((f[i][k])&&(k!=i)) k=i,hehe=false;
if(k==biaoji) {k=biaoji;hehe=true;}
}
for(int i=1;i<=n;i++)
if((!flag[i])&&(f[k][i])) flag[i]=true;
}
printf("%d",sum);
return;
}
int main()
{
init();
floyd();
work();
return 0;
}
可以说我的心情是十分绝妙了。