题干:
小明的贪心题
描述
小明来到青岛上学已经一年了,他给青岛这座城市画了一张地图。在这个地图上有n个点,小明的起始点为1号点,终点为n号点,并且地图上的所有边都是单向的。小明知道从i号点到j号点的时间花费为w分钟,那么问题来了,求从1号点到n号的最小时间花费是多少?这个最少花费的路径有多少条?
输入
输入格式:输入文件第一行为两个空格隔开的数n,m,表示这张地图里有多少个点及有多少边的信息。下面m行,每行三个数I、J、w,表示从I点到J点有道路相连且花费为w.(注意,数据提供的边信息可能会重复,不过保证I<>J,1<=I,J<=n)。1<=N<=2100,0<=m<=N*(N-1), 1<=w<=2100.
输出
输出格式:输出文件包含两个数,分别是最少花费和花费最少的路径的总数.两个不同的最短路方案要求:路径长度相同(均为最短路长度)且至少有一条边不重合。若城市N无法到达则只输出一个(‘No answer’);
输入样例 1
 
5 4
1 5 4
1 2 2
2 5 2
4 1 1 
输出样例 1
 
4 2 
输入样例 2
 
100 1
1 2 1 
输出样例 2
 
No answer 
解题报告:
这题比赛的时候坑的我好苦啊,一个小错误(不过也确实以前都没注意这个小地方,大概还是做双权值的题做少了),最后前十都没进。。。这么简单的一道最短路条数,就因为少了一个vis的if判断,然后就GG思密达。不过还是有很多地方是值得注意的。比如这题需要去重边。(直接邻接矩阵去重边就可以了,因为数据量2000也不算大)
AC代码:
using namespace std;
const int INF = 0x3f3f3f3f; 
const ll INFINF = 0x3f3f3f3f3f3f3f3f;
int n,m,top;
int head[5000 +5];
ll dis[5005],ans[5005];
bool vis[5005];
ll maze[5005][5005];
struct Edge{
  int to,ne;
  ll w;
} e[5000000 +5];
struct point {
  int pos;
  ll c;
  point(){}
  point(int pos,ll c):pos(pos),c(c){}
  bool operator <(const point & b) const {
    return c>b.c;
  }
};
void add(int u,int v,ll w) {
  e[++top].to = v;
  e[top].w=w;
  e[top].ne = head[u];
  head[u] = top;
}
void Dijkstra(int u,int v) {
  priority_queue<point> pq; 
  for(int i = 1; i<=n; i++) dis[i] = INFINF;
  memset(vis,0,sizeof vis);
  memset(ans,0,sizeof ans);
  ans[u]=1;
  dis[u] = 0;
  point cur = point(u,0);
  pq.push(cur);
  while(!pq.empty()) {
    point now = pq.top();pq.pop();
//    if(vis[now.pos] == 1) continue;
    vis[now.pos] = 1;
    for(int i = head[now.pos]; i!=-1; i=e[i].ne) {
      if(vis[e[i].to] == 1) continue;
      if(  dis[e[i].to] > dis[now.pos] + e[i].w ) {
        dis[e[i].to] = dis[now.pos] + e[i].w;
        ans[e[i].to] = ans[now.pos];
        pq.push(point(e[i].to,dis[e[i].to] ) ); 
      }
      else if(dis[e[i].to] == dis[now.pos] + e[i].w) {
        ans[e[i].to] += ans[now.pos];
      }
    } 
  }
  if(dis[v] == INFINF) puts("No answer");
  else {
    printf("%lld %lld\n",dis[v],ans[v]);
  }
} 
int main()
{
  int a,b;
  ll w;
  while(~scanf("%d%d",&n,&m)) {
    top=0;
    memset(head,-1,sizeof head);
//    memset(maze,INF,sizeof maze);
    for(int i = 1; i<=n; i++) {
      for(int j = 1; j<=n; j++) {
        maze[i][j] = INFINF;
      }
    }
    for(int i = 1; i<=m; i++) {
      scanf("%d %d %lld",&a,&b,&w);
      if(maze[a][b]>w) maze[a][b]=w;
    }
    for(int i = 1; i<=n; i++) {
      for(int j = 1; j<=n; j++) {
        if(maze[i][j]<10000) {
          add(i,j,maze[i][j]);
        }
      }
    }
    Dijkstra(1,n); 
  }
  return 0 ;
}
//5 4
//1 5 4
//1 2 2
//2 5 2
//4 1 1AC代码2:
using namespace std;
const int INF = 0x3f3f3f3f; 
const ll INFINF = 0x3f3f3f3f3f3f3f3f;
int n,m,top;
int head[5000 +5];
ll dis[5005],ans[5005];
bool vis[5005];
ll maze[5005][5005];
struct Edge{
  int to,ne;
  ll w;
} e[5000000 +5];
struct point {
  int pos;
  ll c;
  point(){}
  point(int pos,ll c):pos(pos),c(c){}
  bool operator <(const point & b) const {
    return c>b.c;
  }
};
void add(int u,int v,ll w) {
  e[++top].to = v;
  e[top].w=w;
  e[top].ne = head[u];
  head[u] = top;
}
void Dijkstra(int u,int v) {
  priority_queue<point> pq; 
  for(int i = 1; i<=n; i++) dis[i] = INFINF;
  memset(vis,0,sizeof vis);
  memset(ans,0,sizeof ans);
  ans[u]=1;
  dis[u] = 0;
  point cur = point(u,0);
  pq.push(cur);
  while(!pq.empty()) {
    point now = pq.top();pq.pop();
    if(vis[now.pos] == 1) continue;
    vis[now.pos] = 1;
    for(int i = head[now.pos]; i!=-1; i=e[i].ne) {
//      if(vis[e[i].to] == 1) continue;
      if(  dis[e[i].to] > dis[now.pos] + e[i].w ) {
        dis[e[i].to] = dis[now.pos] + e[i].w;
        ans[e[i].to] = ans[now.pos];
        pq.push(point(e[i].to,dis[e[i].to] ) ); 
      }
      else if(dis[e[i].to] == dis[now.pos] + e[i].w) {
        ans[e[i].to] += ans[now.pos];
      }
    } 
  }
  if(dis[v] == INFINF) puts("No answer");
  else {
    printf("%lld %lld\n",dis[v],ans[v]);
  }
} 
int main()
{
  int a,b;
  ll w;
  while(~scanf("%d%d",&n,&m)) {
    top=0;
    memset(head,-1,sizeof head);
//    memset(maze,INF,sizeof maze);
    for(int i = 1; i<=n; i++) {
      for(int j = 1; j<=n; j++) {
        maze[i][j] = INFINF;
      }
    }
    for(int i = 1; i<=m; i++) {
      scanf("%d %d %lld",&a,&b,&w);
      if(maze[a][b]>w) maze[a][b]=w;
    }
    for(int i = 1; i<=n; i++) {
      for(int j = 1; j<=n; j++) {
        if(maze[i][j]<10000) {
          add(i,j,maze[i][j]);
        }
      }
    }
    Dijkstra(1,n); 
  }
  return 0 ;
}
//5 4
//1 5 4
//1 2 2
//2 5 2
//4 1 1总结:
所以保险起见,还是两个if剪枝都写上吧。
                








