1.FloodFill
这一部分没什么好说的,大部分都是水题。
题目:POJ_2386
2.拓扑排序
Fabulous DAGy(UVA11893)
这一题的大概意思就是一种叫做Dagy的有向图,满足以下性质,删去其中的一条边后是有向无环图,且这个图存在一个环,这个环能够包含图上的所有节点。问输入的图是否满足性质。
题解:
1.如果存在入度为0的结点,则一定不是Dagy图。(该点必定无法被包含在环内)
2.枚举所有入度为1的结点,删去指向它的边(不用真的删去),则它的入度为0.
3.对某一次删除,结点U入度为0。从u开始做拓扑排序。若某一时刻,存在>=2个结点入度为0,则这两个点一定不在同一个环内。则这次删除不符合性质,返回到第2步。若某一时刻,对于入度为0的点u,存在边(u,v),v=U,则说明返回到了起始点,此时判断经过的点个数是否等于N,是则满足性质,否则返回第二步。
#include <iostream>
#include <cstring>
#define maxn 405
using namespace std;
int e,now,n,m,uu,u1;
int f[maxn];
int visit[maxn];
int ru[maxn],r1[maxn],chu[maxn],q[maxn];
int a[maxn][maxn];
int main()
{
int tt,t;
cin>>tt;
while (tt--)
{
memset(ru,0,sizeof(ru));
memset(chu,0,sizeof(chu));
memset(f,0,sizeof(f));
memset(a,0,sizeof(a));
cin>>n>>m;
while (m--)
{
int x,y;
cin>>x>>y;
chu[x]++;
ru[y]++;
a[x][y]=1;
}
int i;
for (i=0;i<n;i++)
if (ru[i]==0)
break;
if (i==n)
{
for (i=0;i<n;i++)
if (ru[i]==1)
{
int now,now1;
for (int j=0;j<n;j++)
r1[j]=ru[j];
now=i;
t=1;
int tot=0;
while (t==1)
{
for (int j=0;j<n;j++)
if (a[now][j])
{
r1[j]--;
if (r1[j]==0)
{
tot++;
t++;
now1=j;
if (t>2) break;
}
}
t--;
if (t>1) break;
now=now1;
if (tot==n && now==i) t=-1;
}
if (t==-1) break;
}
// uu=i;
if (t==-1)
cout<<"Yeah, I'm superman"<<endl;else
cout<<"Your DAGy was initially defected!"<<endl;
} else cout<<"Your DAGy was initially defected!"<<endl;
}
//while (1);
return 0;
}
/*
100
5 5
0 1
1 2
1 3
3 4
4 0
5 6
0 1
1 2
2 3
3 4
1 4
4 0
*/
题目:POJ_3249
3.MST(最小生成树)
Qin Shi Huang's National Road System(hdu_4081)
题目大意是给出一张图,每个点都有一个权值,以及点的坐标(x,y),通过一条边将其中的两个点连接起来(magic road),且这条边代价为0,并用n-2条边使整个图联通,这n-2条边的代价为连接的两个点的距离。假设magic road连接的两个点权值分别为a,b,n-2条边的代价和为cost,求(a+b)/cost的最大值
题解:
先得到这个图的最小生成树,O(N^2),初始ans为INF,枚举添加的边E(u,v),则添加的边与最小生成树会形成一个环,删除环上代价最大的边(prim的同时用path[i][j]预处理出来就好),则得到的值为(a+b)/(tot-path[u][v]),若小于ans则更新,a,b为u,v的权值,tot为最小生成树的总代价,path[u][v]为环上代价最大的边。答案即为ans。
#include <iostream>
#include <cmath>
#include <cstdio>
#define maxn 1005
#define MAX 1000000000
#define max(a,b) (a)>(b)?(a):(b)
using namespace std;
double path[maxn][maxn];
int visit[maxn],pre[maxn],x[maxn],y[maxn],p[maxn];
double a[maxn][maxn],dis[maxn];
int main()
{
int tt;
cin>>tt;
while (tt--)
{
int n;
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>x[i]>>y[i]>>p[i];
//graph[x].clear();
}
//index=-1;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
//node x;
double p=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
//x.val=sqrt(p);
//x.pos=j;
//graph[x].push_back(x);
a[i][j]=sqrt(p);
path[i][j]=0;
}
for (int i=1;i<=n;i++)
{
dis[i]=MAX;
visit[i]=0;
pre[i]=i;
}
// memset(path,0,sizeof(path));
dis[1]=0;
double tot=0;
int u;
for (int i=1;i<=n;i++)
{
double min=MAX;
for (int j=1;j<=n;j++)
if (!visit[j] && dis[j]<min)
{
min=dis[j];
u=j;
}
visit[u]=1;
tot+=min;
int k=pre[u];
for (int j=1;j<=n;j++)
if (u!=j && visit[j])
path[u][j]=path[j][u]=max(path[j][k],min);
for (int j=1;j<=n;j++)
if (!visit[j] && a[u][j]<dis[j])
{
dis[j]=a[u][j];
pre[j]=u;
}
}
double ans=0;
for (int i=1;i<=n;i++)
for (int j=i+1;j<=n;j++)
{
double p1=(p[i]+p[j])*1.0/(tot-path[i][j]);
if (p1>ans) ans=p1;
}
printf("%.2lf\n",ans);
}
// while (1);
return 0;
}
题目: POJ_2349
4.最短路
差分约束:(POJ_1201POJ_1275POJ_2983)
这一类型题没什么好说的,建好图套一个SPFA或者bellman-ford即可。
5.强连通分量
Ikki's Story IV - Panda's Trick (hdu_4081)
题意:平面上,一个圆,圆的边上按顺时针放着n个点。现在要连m条边,比如a,b,那么a到b可以从圆的内部连接,也可以从圆的外部连接。给你的信息中,每个点最多只会连接的一条边。问能不能连接这m条边,使这m条边不相交。
将每条边拆成i,i',i表示从内部连接,i'表示外部连接,那么对于i,j,如果i,j放在一边会相交,则i->j',i'->j,j->i',j'->i,连接这四条边,然后就是2-sat算法了。
#include <iostream>
#include <cstring>
#include <vector>
#define MIN(a,b) (a)<(b)?(a):(b)
#define maxn 1005
using namespace std;
vector <int> graph[maxn];
int visit[maxn],q[maxn],que[maxn],c[maxn],dfn[maxn],low[maxn],index,tail,color;
struct node
{
int l,r;
} e[maxn];
void insert(int u,int v)
{
graph[u].push_back(v);
}
void tarjan(int u)
{
dfn[u]=low[u]=++index;
visit[u]=1;
q[++tail]=u;
que[u]=1;
for (int i=0;i<graph[u].size();i++)
{
int p=graph[u][i];
if (!visit[p])
{
tarjan(p);
low[u]=MIN(low[u],low[p]);
} else
if (que[p])
low[u]=MIN(low[u],dfn[p]);
}
int y;
if (low[u]==dfn[u])
{
color++;
do
{
y=q[tail];
que[y]=0;
c[y]=color;
tail--;
} while (y!=u);
}
}
int main()
{
int n,m;
cin>>n>>m;
for (int i=1;i<=m;i++)
{
cin>>e[i].l>>e[i].r;
if (e[i].l>e[i].r) {int temp=e[i].l;e[i].l=e[i].r;e[i].r=temp;}
}
for (int i=1;i<=2*m;i++)
graph[i].clear();
for (int i=1;i<=m-1;i++)
for (int j=i+1;j<=m;j++)
{
if (e[i].l<e[j].l && e[i].r>e[j].l && e[i].r<e[j].r ||
e[i].l>e[j].l && e[i].r>e[j].r && e[i].l<e[j].r)
{
insert(i,j+m);
insert(i+m,j);
insert(j,i+m);
insert(j+m,i);
}
}
memset(visit,0,sizeof(visit));
memset(q,0,sizeof(q));
memset(que,0,sizeof(que));
tail=-1;index=0;color=0;
for (int i=1;i<=2*m;i++)
if (!visit[i])
tarjan(i);
int i;
for (i=1;i<=m;i++)
if (c[i]==c[i+m]) break;
if (i<=m) cout<<"the evil panda is lying again"<<endl;else
cout<<"panda is telling the truth..."<<endl;
return 0;
}
题目: POJ_2186 POJ_1236