斯坦福 算法2 第一周作业

来自斯坦福网站的Algorithms: Design and Analysis,与目前coursera上的版本内容没有变化,不过时间安排略有不同。

1. Problem Set 1

斯坦福 算法2 第一周作业
按照提示,RjR_{j}表示按结束时间升序排序的第j个任务,设其结束时间为SjS_{j}。那么这个任务占用的时间就是[Sj1,Sj][S_{j-1},S_{j}]。其它的任何任务i占用的时间都是[Sj1,Si][S_{j-1},S_{i}],而根据设定SiSjS_{i} \geq S_{j},也就是说选择RjR_{j}占用的时间段初试时间与其它所有任务相同,而结束时间比选择其它的都短,因此与最少的任务重叠。

斯坦福 算法2 第一周作业
刚开始我觉得应该按djpjd_{j}-p_{j}来排序,后来发现用djd_{j}就可以了。证明过程与课程中的证明很类似。按照djd_{j}升序得到的解法α\alpha的表示为[1,2,3,…,n],而假设最优解α\alpha*α\alpha不同。那么就最优解α\alpha*中就必然存在至少一个连续的逆序对i,j使得di>djd_{i} > d_{j}。i前一个任务i-1的结束时间为Ci1C_{i-1},i之前与j之后的人物的ll值不受影响。我们只需要关注max(li,lj)max(l_{i},l_{j})的结果。

在最优解法α\alpha*下任务i先执行,j后执行。因此max(li,lj)=max(Ci1+pidi,Ci1+pi+pjdj)max(l_{i}^{*},l_{j}^{*}) = max(C_{i-1}+p_{i}-d_{i}, C_{i-1}+p_{i}+p_{j}-d_{j}) 。假如交换i与j的执行顺序,那么得到新的max(li,lj)=max(Ci1+pjdj,Ci1+pi+pjdi)max(l_{i},l_{j}) = max(C_{i-1}+p_{j}-d_{j}, C_{i-1}+p_{i}+p_{j}-d_{i})。因为di>djd_{i} > d_{j},所以lj=Ci1+pi+pjdj>li=Ci1+pjdjl_{j}^{*} = C_{i-1}+p_{i}+p_{j}-d_{j} > l_{i} = C_{i-1}+p_{j}-d_{j},同时lj=Ci1+pi+pjdj>lj=Ci1+pi+pjdil_{j}^{*} = C_{i-1}+p_{i}+p_{j}-d_{j} > l_{j} = C_{i-1}+p_{i}+p_{j}-d_{i}。于是得到max(li,lj)>max(li,lj)max(l_{i}^{*},l_{j}^{*}) > max(l_{i},l_{j}),也就是说交换后的策略更好,与假设最优解α\alpha*与贪心结果α\alpha不同矛盾。得证。

斯坦福 算法2 第一周作业
用心感受。

斯坦福 算法2 第一周作业
子图中的最小生成树T的边可能无法组成一个联通图,因此有可能不是一个生成树。但是因为The Cut Property,子图内部的T的每条边肯定依然是最小的,因此就是子图的生成树的组成部分。

斯坦福 算法2 第一周作业
仔细想想不难。

2. Optional Theory Problems

斯坦福 算法2 第一周作业
告辞。

3. Programming Assignment 1

3.1 3.2 课程中的scheduling 问题

#include <iostream>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <fstream>
#include <sstream>
#include <set>
#include <string>
#include <ctime>
#include <algorithm>

using namespace std;

#define INT_MAX 2147483647


void readData(string fileName,vector<pair<int,int>>& v) {
    cout << "read data from "<< fileName <<endl;
    ifstream input(fileName);
    string line;
    int weight, length;
    getline(input,line); //num
    if(input) {
        while(getline(input,line)) {
            istringstream ist(line);
            ist >> weight >> length;
            v.push_back({weight,length});
        }
    }
    cout << "reading data finished."<<endl;
}

bool divcmp(pair<int,int>& a, pair<int,int>& b) {
    double score1 = double(a.first)/a.second;
    double score2 = double(b.first)/b.second;
    return score1 > score2;
}

bool diffcmp(pair<int,int>& a, pair<int,int>& b) {
    double score1 = a.first-a.second;
    double score2 = b.first-b.second;
    if(score1 == score2)
        return a.first > b.first;
    return score1 > score2;
}

void weightSum(vector<pair<int,int>>& v) {
    vector<pair<int,int>> v1 = v;
    
    cout << "sort jobs according to difference ..."<<endl;
    sort(v.begin(),v.end(),diffcmp);
    cout << "sort finished."<<endl;
    long long sum1 = 0, t = 0;
    for(int i = 0; i < v.size(); i++) {
        t += v[i].second;
        sum1 += t*v[i].first;
    }

    cout << "problem1 res: "<< sum1 << endl;
    
    cout << "sort jobs according to divide ... "<<endl;
    sort(v1.begin(),v1.end(),divcmp);
    cout << "sort finished."<<endl;
    long long sum2 = 0;
    t = 0;
    for(int i = 0; i < v1.size(); i++) {
        t += v1[i].second;
        sum2 += t*v1[i].first;
    }
    cout << "problem2 res: "<< sum2 << endl;
}

int main() {
    string fileName = "jobs.txt";
    vector<pair<int,int>> v;
    readData(fileName,v);
    weightSum(v);
    return 0;
}

3.3 Prim 算法

只实现了naive版本的。heap加速写起来还是太麻烦。

#include <iostream>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <fstream>
#include <sstream>
#include <set>
#include <string>
#include <ctime>
#include <algorithm>

using namespace std;

#define INT_MAX 2147483647


void readGraph(string fileName,unordered_map<int,vector<pair<int,int>>>& G) {
    cout << "read data from "<< fileName <<endl;
    ifstream input(fileName);
    string line;
    int u,v,weight;
    if(input) {
        getline(input,line);
        while(getline(input,line)) {
            istringstream ist(line);
            ist >> u >> v >> weight;
            G[u-1].push_back({v-1,weight});
            G[v-1].push_back({u-1,weight});
        }
    }
}


long long prim(unordered_map<int,vector<pair<int,int>>>& G, int start) {
    int N = G.size();
    long long res = 0;
    vector<int> visited(N);
    vector<int> curDis(N,INT_MAX);

    curDis[start] = 0;
    int visitedCount = 0;
    int next,nextDis;

    while(visitedCount < G.size()) {
        next = -1;
        nextDis = INT_MAX;
        for(int i = 0; i < N; i++)
            if(visited[i] == 0 && curDis[i] < nextDis) {
                nextDis = curDis[i];
                next = i;
            }
        
        visited[next] = 1;
        res += nextDis;
        visitedCount++;
        if(next == -1) break;

        for(int k = 0; k < G[next].size(); k++) {
            auto p = G[next][k];
            if(!visited[p.first])
                curDis[p.first] = min(curDis[p.first],p.second);
        }
    }
    return res;
}

int main() {
    string fileName = "edges.txt";
    unordered_map<int,vector<pair<int,int>>> G(500);
    readGraph(fileName,G);

    long long res = prim(G,0);
    cout << "prim res: "<< res << endl;
    return 0;
}