ZOJ: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1298
POJ: http://poj.org/problem?id=1135
总是从n=1的骨牌开始推倒。
输出最后倒下的骨牌的倒下时间和位置(最后倒下的是某个关键骨牌,或者某两个关键骨牌之间)
解题思路:
首先每个key domino什么时候倒下可以抽象为一个最短路问题,可以用Dijkstra, BellmanFord或者SPFA算出每个key domino倒下的时间。
接下来计算最后倒下骨牌的位置。由于“If you find several solutions, output only one of them.”,注意到答案可能不只一个,所以我枚举计算了
1、每条边最后倒下骨牌倒下的时间(如果边i->j,有dis[i]>dis[j]-w[i][j],说明不是从i倒到j,那么最后倒下的骨牌才是between i and j)
2、每个key domino倒下的时间
这一步应该有更简单的方法,或者放在最短路里做,但是数据量不大,就这么乱搞了……
注意点
1、边界问题,要测试n==1的时候能不能正常输出,我因为这个WA了一次……
2、输出后加一空行
3、分情况输出的时候,加n==1的时候匆匆忙忙System # 这一行漏了一次……
源代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <limits.h>
using namespace std;
#define maxn 510
struct edge{int v,w,next;};
bool init(int g[], edge e[],int &n, int &m)
{
scanf("%d%d", &n, &m);
if (n==0 && m==0) return false;
memset(g,255,sizeof(*g)*n);
for(int i=0,j=0; i<m;i++)
{
int a,b,c;
scanf("%d%d%d", &a, &b, &c);
a--; b--;
e[j].v=b; e[j].w=c; e[j].next=g[a]; g[a]=j++;
e[j].v=a; e[j].w=c; e[j].next=g[b]; g[b]=j++;
}
return true;
}
bool bellmanford(int g[], edge e[], int n, int s, int dis[])
{
bool u[maxn]={0};
int q[maxn], c[maxn]={0}, h=0, d=1;
for (int i=0; i<n; i++)
dis[i]=INT_MAX;
dis[s]=0; u[s]=true; q[0]=s;
while (h!=d)
{
int i=q[h];
if (++h==n+1) h=0;
u[i]=false;
if (c[i]++==n) return false;
for (int j=g[i],k; j!=-1; j=e[j].next)
if (dis[k=e[j].v]>dis[i]+e[j].w)
{
dis[k]=dis[i]+e[j].w;
if (!u[k]) {u[k]=true; q[d++]=k; if(d==n+1) d=0;}
}
}
return true;
}
void solve(int g[], edge e[], int cs, int n, int dis[])
{
printf("System #%d\n", cs);
int k=0, k1, k2;
double time1=0.0, time2=0.0;
//check the last falling key domino
for (int i=1; i<n; i++)
if (dis[i]>dis[k]) k=i;
time1=1.0*dis[k];
//check domino between key dominoes
for (int i=0; i<n; i++)
for (int j=g[i]; j!=-1; j=e[j].next)
{
if (dis[e[j].v]<=dis[i] && dis[e[j].v]>dis[i]-e[j].w && 1.0*(dis[e[j].v]+dis[i]+e[j].w)/2>time2)
{
time2=1.0*(dis[e[j].v]+dis[i]+e[j].w)/2;
k1=(i<e[j].v)?i:e[j].v;
k2=(i>e[j].v)?i:e[j].v;
}
}
if (time1>time2)
printf("The last domino falls after %.1lf seconds, at key domino %d.\n\n", time1, k+1);
else
printf("The last domino falls after %.1lf seconds, between key dominoes %d and %d.\n\n", time2, k1+1, k2+1);
}
int main(){
int g[maxn], dis[maxn];
edge e[maxn*maxn];
int n, m;
for (int cs=1; ;cs++)
{
if (!init(g, e, n, m)) break;
if (n==1)
{
printf("System #%d\n", cs);
printf("The last domino falls after 0.0 seconds, at key domino 1.\n\n");
continue;
}
bellmanford(g, e, n, 0, dis);
solve(g, e, cs, n, dis);
}
return 0;
}