ichirin2501's diary

いっちりーん。

Course Planning for Lazy Students

http://rose.u-aizu.ac.jp/onlinejudge/ProblemSet/description.jsp?id=1032&lang=jp
University of Aizu, ACM-ICPC Japan Domestic Contest Warm Up I, 16 May, 2009

//簡易コード TLE版
#include <iostream>
#include <vector>
#include <climits>
using namespace std;

int main()
{
   int N,U,K;
   while(cin>>N>>U,N|U){
      pair<int, vector<int> > piv[N];
      int ans = INT_MAX;
      for(int i=0; i<N; i++){
         cin>>piv[i].first>>K;
         for(int j=0; j<K; j++){
            int a; cin>>a; piv[i].second.push_back(a);
         }
      }
      for(int i=1; i<(1<<N); i++){
         int cnt = 0;
         int sum = 0;
         int tmp = 0;
         for(int j=0; (1<<j)<=i; j++){
            if( i&(1<<j) ){
               tmp++;
               if( tmp>ans )break;
               int k;
               for(k=0; k<piv[j].second.size(); k++)
                  if( !(i&(1<<piv[j].second[k])) )break;
               if( k==piv[j].second.size() ){
                  sum += piv[j].first; cnt++;
               }
            }
         }
         if( tmp==cnt && sum>=U && ans>cnt){
            ans = cnt;
         }
      }
      printf("%d\n",ans);
   }
   return 0;
}

組み合わせを列挙後、条件を満たしてるかのチェックをするアルゴリズム
AOJだと、8秒ぐらいかかってTLE。答えはたぶん合ってる。
N<=20なので、ビットを使った組み合わせで綺麗に書ける。
まぁ、だめなんだけどw

//何故がAcceptもらったよくわからないコード。
#include <iostream>
#include <vector>
#include <climits>
#include <cstring>
using namespace std;

int N,U,C,K;
int ans;
pair<int, vector<int> > pivv[32];

void dfs(int now, int nowcost, int cnt, int next)
{
   if( ans<cnt )return;
   if( nowcost>=U ){ ans = cnt; return; }
   for(int i=next; i<N; i++){
      if( !(now&(1<<i)) ){
         int j;
         for(j=0; j<pivv[i].second.size(); j++)
            if( !(now&(1<<pivv[i].second[j])) )break;
         if( j==pivv[i].second.size() ){
            dfs(now|(1<<i), nowcost+pivv[i].first, cnt+1, i+1);
         }
      }
   }
   return;
}

int main()
{
   while(cin>>N>>U, N|U){
      pair<int, vector<int> > piv[N];
      ans = INT_MAX;
      for(int i=0; i<N; i++){
         cin>>piv[i].first>>K;
         for(int j=0; j<K; j++){
            int a; cin>>a;
            piv[i].second.push_back(a);
         }
      }
      
      // sort
      pair<int, vector<int> > tmp[N],pivtmp[N];
      vector<int> cv;
      int check[N];
      memset(check,0,sizeof(check));
      for(int i=0; i<N; i++)pivtmp[i]=piv[i];
      
      for(int i=0; i<N; i++){
         int pos=-1,tmin=N+1;
         for(int j=0; j<N; j++){
            int k;
            int c = 0;
            int n = pivtmp[j].second.size();
            
            for(k=0; k<n; k++){
               int l;
               for(l=0; l<i; l++)
                  if( cv[l]==pivtmp[j].second[k] )break;
               if( l<i || l==0 )c++;
            }
            
            if( c==n && tmin>n && !check[j]){
               pos = j; tmin = n;
            }
         }

         for(int j=0; j<N; j++){
            if( check[j] )continue;
            for(int l=0; l<pivtmp[j].second.size(); l++){
               if( pivtmp[j].second[l]==pos )
                  piv[j].second[l] = i;
            }
         }
         tmp[i] = piv[pos];
         check[pos] = 1;
         cv.push_back(pos);
      }

      for(int i=0; i<N; i++)pivv[i] = tmp[i];
      dfs(0,0,0,0);
      printf("%d\n",ans);
   }
   return 0;
}

解法は変にソート後、dfs+枝切り。
ソートの優先順位は、
・必修科目がない科目の集合
・↑の集合を用いて受講できる科目の集合
・↑の集合を用いて受講でき(ry

みたいな流れでソートさせても、組み合わせを探索したら
データセットによっては処理が終わらない、と思う。
AOJの判定データはよくない。
バグありのコードでもAcceptもらうことがある。
バグが発生するケースを自分で考えられない奴が文句言うな><

鬱だにゃ。