程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> hdu Minimum Transport Cost(按字典序輸出路徑)

hdu Minimum Transport Cost(按字典序輸出路徑)

編輯:C++入門知識

 

求最短路,要求輸出字典序最小的路徑。

 

spfa:拿一個pre[]記錄前驅,不同的是在松弛的時候,要考慮和當前點的dis值相等的情況,解決的辦法是dfs找出兩條路徑中字典序較小的,pre[]去更新。把路徑當做字符串處理。

我只用之前的pre去更新當前點,並沒考慮到起點到當前點的整個路徑,其實這樣並不能保證是字典序最小。wa了N次,於是乎搜了下題解,發現用spfa解的很少,看到了某大牛的解法如上,感覺很贊的想法。

 

 

#include 
#include 
#include 
#include
#include 
#include 
#include 
#include 
#define LL long long
#define _LL __int64
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 110;

int n;
int tax[maxn];
int Map[maxn][maxn];
int dis[maxn],inque[maxn];
int pre[maxn];
int pos = 0;

void dfs(int u, char *s)
{
	if(u == -1)
		return;
	dfs(pre[u],s);
	s[pos++] = u+'0';
}

bool solve(int v, int u)
{
	char s1[maxn],s2[maxn];
    
    //尋找先前的路徑
	pos = 0;
	dfs(v,s1);
	s1[pos] = '';
    //尋找由u更新的路徑
	pos = 0;
	dfs(u,s2);
	s2[pos++] = v+'0';
	s2[pos] = '';

	if(strcmp(s1,s2) > 0) return true;
	return false;

}

int spfa(int s, int t)
{
	queue  que;
	memset(dis,INF,sizeof(dis));
	memset(inque,0,sizeof(inque));
	memset(pre,-1,sizeof(pre));

	dis[s] = 0;
	inque[s] = 1;
	que.push(s);

	while(!que.empty())
	{
		int u = que.front();
		que.pop();
		inque[u] = 0;

		for(int v = 1; v <= n; v++)
		{
			if(Map[u][v] > 0)
			{
				int tmp = dis[u] + Map[u][v] + tax[v];

				if(tmp < dis[v])//直接更新
				{
					dis[v] = tmp;
					pre[v] = u;
					if(!inque[v])
					{
						inque[v] = 1;
						que.push(v);
					}
				}
				else if(tmp == dis[v] && solve(v,u))
				{
					pre[v] = u;
				}

			}
		}
	}

	return dis[t];
}

void output(int s, int t)
{
	int res[maxn];
	int cnt = 0;
	int tmp = t;

	while(pre[tmp] != -1)
	{
		res[cnt++] = tmp;
		tmp = pre[tmp];
	}
	res[cnt] = s;
	printf(Path: );
	for(int i = cnt; i >= 1; i--)
		printf(%d-->,res[i]);
	printf(%d
,res[0]);
}

int main()
{
	while(~scanf(%d,&n) && n)
	{
		for(int i = 1; i <= n; i++)
		{
			for(int j = 1; j <= n; j++)
				scanf(%d,&Map[i][j]);
		}
		for(int i = 1; i <= n; i++)
			scanf(%d,&tax[i]);
		int u,v;
		while(~scanf(%d %d,&u,&v))
		{
			if(u == -1 && v == -1) break;
			int tmp1 = tax[u];//備份
			int tmp2 = tax[v];
			
			tax[u] = 0;
			tax[v] = 0;

			printf(From %d to %d :
,u,v);
			int ans = spfa(u,v);
			output(u,v);
			printf(Total cost : %d

,ans);
            //恢復備份
			tax[u] = tmp1;
			tax[v] = tmp2;


		}
	}
	return 0;
}

 

 


floyd:pre[i][j]記錄i到j路徑上距離i最近的點,輸出路徑時按pre正向輸出。感覺floyd很強大啊,還可以這樣記錄路徑。

 

 

#include 
#include 
#include 
#include
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define _LL __int64
using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn =  110;
int Map[maxn][maxn];
int tax[maxn];
int pre[maxn][maxn];
int n;


void floyd()
{
    //初始化
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            pre[i][j] = j;

    for(int k = 1; k <= n; k++)
    {
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= n; j++)
            {
                if(Map[i][k] > 0 && Map[k][j] > 0)
                {
                    int tmp = Map[i][k] + Map[k][j] + tax[k];

                    if(tmp < Map[i][j]) //小於直接更新
                    {
                        Map[i][j] = tmp;
                        pre[i][j] = pre[i][k];
                    }
                    else if(tmp == Map[i][j]) 
                    {
                        pre[i][j] = min(pre[i][k],pre[i][j]);
                    }
                }
            }
        }
    }
}

void output(int s, int t)
{
    printf(Path: );
    int tmp = s;
    while(tmp != t)
    {
        printf(%d-->,tmp);
        tmp = pre[tmp][t];
    }
    printf(%d
,t);

}

int main()
{
    while(~scanf(%d,&n) && n)
    {
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
            {
                scanf(%d,&Map[i][j]);
                if(Map[i][j] == -1)
                    Map[i][j] = INF;
            }

        for(int i = 1; i <= n; i++)
            scanf(%d,&tax[i]);

        int u,v;
        floyd();
        while(~scanf(%d %d,&u,&v))
        {
            if(u == -1 && v == -1) break;
            printf(From %d to %d :
,u,v);
            output(u,v);
            printf(Total cost : %d

,Map[u][v]);
        }
    }
    return 0;
}


 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved