2012 Multi-University Training Contest 8[hdu4370~4379]

4370 0 or 1

就2種情況, 一種是1到n的最短路, 一種是包含1的環和包含n的環, 第一種情況直接sssp就好, 第二種比較好的處理方法就是枚舉環的一個點, 然後用sssp得到的dist數組去求2個最小環, 相加即可,我的方法是再跑遍floyd, 不過要用dist優化一下, 提前排除不是最優解的情況, 1600ms水過

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <map>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

const int oo=2000000000;
const int maxn=100000+123;
const int inf=0x5fffffff;
int a[333][333];
struct Edge{
    int v, w, next;
}edge[maxn*2];
int head[maxn], cnt;

struct Node{
    int u, w;
    bool operator < (Node a)const
    {
        return w > a.w;
    }
};

void addedge(int u, int v, int w)
{
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
int dist[maxn];
void Dijkstra(int s, int n)//0到n-1 s是源點
{
    for (int i=0; i<n; ++i)
        dist[i]=inf;
    dist[s]=0;
    priority_queue<Node> q;
    Node cur;
    cur.u=s; cur.w=0;
    q.push(cur);
    while (!q.empty())
    {
        cur=q.top();
        q.pop();
        if(dist[cur.u]<cur.w)continue;
        for (int p=head[cur.u]; ~p; p=edge[p].next)
            if(dist[edge[p].v]>dist[cur.u]+edge[p].w)
            {
                dist[edge[p].v]=dist[cur.u]+edge[p].w;
                Node tmp;
                tmp.u=edge[p].v;
                tmp.w=dist[edge[p].v];
                q.push(tmp);
            }
    }
    //for (int i=0; i<n; ++i)cout << dist[i] << " ";
    //cout << endl;
}


int main()
{
	int n,t;
	while (~scanf("%d",&n))
	{
	    memset (head, -1, sizeof(head));
	    cnt=0;
		for (int i=0;i<n;i++)
			for (int j=0;j<n;j++)
			{
				scanf("%d",&a[i][j]);
                addedge(i, j, a[i][j]);
			}
        Dijkstra(0, n);

		for (int k=0;k<n;k++)
			for (int i=0;i<n;i++)if(a[i][k]<dist[n-1])
				for (int j=0;j<n;j++)if(a[k][j]<dist[n-1])
					if (a[i][j]>a[i][k]+a[k][j])
						a[i][j]=a[i][k]+a[k][j];
		/*for (int i=0;i<n;i++)
		{
			for (int j=0;j<n;j++)
				printf("%d ",a[i][j]);
			printf("\n");
		}*/
		int ans=a[0][n-1];
        int tmp1=oo, tmp2=oo;
		for (int i=0; i<n; ++i)
        {
            if(i)tmp1=min(a[0][i]+a[i][0], tmp1);
            if(i!=n-1)tmp2=min(a[n-1][i]+a[i][n-1], tmp2);
        }
        ans=min(ans, tmp1+tmp2);
		printf("%d\n",ans);
	}
	return 0;
}


4371 Alice and Bob 博弈, 可以想到如果某次不取最小值去加,那麼下手下一步一定有棋可走,  所以雙方都每次都選擇加最小值是不影響勝局的。


hdu4374 One hundred layer  dp 單調隊列優化

int M[123][12345];
int dp[123][12345];
int sum[12345];
int l[12345];
int r[12345];
int inl[12345];
int inr[12345];

int main ()
{
    int n, m, x, t;
    while (~scanf("%d%d%d%d", &n, &m, &x, &t))
    {
        for (int i=0; i<n; ++i)
        {
            for (int j=1; j<=m; ++j)
            {
                scanf("%d", &M[i][j]);
                dp[i][j]=-inf;
            }
        }
        dp[0][x]=0;
        sum[0]=0;
        for (int i=1; i<=m; ++i)
        {
            suf[m-i+1]=M[0][m-i+1]+suf[m-i+2];
            dp[n][i]=-inf;
            //printf("sss==%d ", suf[m-i+1]);
            sum[i]=M[0][i]+sum[i-1];
        }
        for (int i=1; i<=m; ++i)
        {
            l[i]=dp[0][i]-sum[i-1];
            r[i]=dp[0][i]+sum[i];
        }
        for (int i=1; i<=n; ++i)
        {
            int head=1, rear=0;
            for (int j=1; j<=m; ++j)
            {
                while (head<=rear && l[inl[rear]]<=l[j])rear--;
                inl[++rear]=j;
                while (head<=rear && inl[head]<j-t)head++;
//                for (int k=head; k<=rear; ++k)
//                    printf("l[%d]=%d  ", inl[k], l[inl[k]]+sum[j]);
//                printf("ll %d   head=%d, rear==%d\n", j, head, rear);
                dp[i][j]=max(l[inl[head]]+sum[j], dp[i][j]);
            }
            int top=1, tail=0;
            for (int j=m; j>=1; --j)
            {

                while (top<=tail && r[inr[tail]]<=r[j])tail--;
                inr[++tail]=j;
                while (top<=tail && inr[top]>j+t)top++;
                dp[i][j]=max(r[inr[top]]-sum[j-1], dp[i][j]);

//                for (int k=top; k<=tail; ++k)
//                    printf("%d  ", r[inr[k]]-sum[j-1]);
//                printf("rr i==%d j==%d\n", i, j);
            }

            for (int j=1; j<=m; ++j)
            {
                sum[j]=M[i][j]+sum[j-1];
            }
            for (int j=1; j<=m; ++j)
            {
                l[j]=dp[i][j]-sum[j-1];
                r[j]=dp[i][j]+sum[j];
            }
        }
//        for (int i=0; i<=n; ++i)
//        {
//            for (int j=1; j<=m; ++j)
//                printf("%d ", dp[i][j]);
//            puts("");
//        }
        int ans=-inf;

        for (int j=1; j<=m; ++j)
            ans=max(dp[n][j], ans);
        printf("%d\n", ans);
    }
    return 0;
}
/*
3 3 2 1
7 8 1
4 5 6
1 2 3
3 3 2 1
7 -8 10
4 5 6
1 2 3
3 3 2 1
-1 -1 -1
-1 -1 -1
-1 -1 -1
*/


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章